Skip to content

Commit 2c4ce67

Browse files
committed
[test] Improve actions-tree-shaking tests
1 parent 2e08633 commit 2c4ce67

File tree

7 files changed

+185
-166
lines changed

7 files changed

+185
-166
lines changed

test/production/app-dir/actions-tree-shaking/_testing/utils.ts

Lines changed: 56 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,89 @@
1-
// @ts-ignore avoid ts errors during manual testing
2-
import { type NextInstance } from 'e2e-utils'
1+
import { nextTestSetup, type NextInstance } from 'e2e-utils'
2+
3+
// This is from 'next/dist/build/webpack/plugins/flight-client-entry-plugin', but unfortunately
4+
// Typescript breaks when importing it directly.
5+
type Actions = {
6+
[actionId: string]: {
7+
exportedName?: string
8+
filename?: string
9+
workers: {
10+
[name: string]: {
11+
moduleId: string | number
12+
async: boolean
13+
}
14+
}
15+
layer: {
16+
[name: string]: string
17+
}
18+
}
19+
}
320

421
async function getActionsMappingByRuntime(
522
next: NextInstance,
623
runtime: 'node' | 'edge'
7-
) {
24+
): Promise<Actions> {
825
const manifest = JSON.parse(
926
await next.readFile('.next/server/server-reference-manifest.json')
1027
)
1128

1229
return manifest[runtime]
1330
}
1431

15-
export function markLayoutAsEdge(next: NextInstance) {
16-
beforeAll(async () => {
17-
await next.stop()
18-
const layoutContent = await next.readFile('app/layout.js')
19-
await next.patchFile(
20-
'app/layout.js',
21-
layoutContent + `\nexport const runtime = 'edge'`
22-
)
23-
await next.start()
32+
export function nextTestSetupActionTreeShaking(opts) {
33+
let result = nextTestSetup({
34+
...opts,
35+
skipStart: !!process.env.TEST_EDGE,
2436
})
25-
}
2637

27-
/*
28-
{
29-
[route path]: { [layer]: Set<workerId> ]
30-
}
31-
*/
32-
type ActionsMappingOfRuntime = {
33-
[actionId: string]: {
34-
workers: {
35-
[route: string]: string
36-
}
37-
layer: {
38-
[route: string]: string
39-
}
38+
if (process.env.TEST_EDGE) {
39+
beforeAll(async () => {
40+
const layoutContent = await result.next.readFile('app/layout.js')
41+
await result.next.patchFile(
42+
'app/layout.js',
43+
layoutContent + `\nexport const runtime = 'edge'`
44+
)
45+
await result.next.start()
46+
})
4047
}
48+
49+
return result
4150
}
51+
4252
type ActionState = {
4353
[route: string]: {
44-
[layer: string]: number
54+
[layer: string]: string[]
4555
}
4656
}
4757

48-
function getActionsRoutesState(
49-
actionsMappingOfRuntime: ActionsMappingOfRuntime
50-
): ActionState {
58+
function getActionsRoutesState(actionsMappingOfRuntime: Actions): ActionState {
5159
const state: ActionState = {}
52-
Object.keys(actionsMappingOfRuntime).forEach((actionId) => {
60+
for (const actionId in actionsMappingOfRuntime) {
5361
const action = actionsMappingOfRuntime[actionId]
54-
const routePaths = Object.keys(action.workers)
55-
56-
routePaths.forEach((routePath) => {
62+
for (const routePath in action.workers) {
5763
if (!state[routePath]) {
5864
state[routePath] = {}
5965
}
6066
const layer = action.layer[routePath]
6167

6268
if (!state[routePath][layer]) {
63-
state[routePath][layer] = 0
69+
state[routePath][layer] = []
6470
}
6571

66-
state[routePath][layer]++
67-
})
68-
})
72+
// Normalize when NEXT_SKIP_ISOLATE=1
73+
const filename = action.filename.startsWith('test/tmp/next-test-')
74+
? action.filename.slice(
75+
action.filename.indexOf('/', 'test/tmp/next-test-'.length) + 1
76+
)
77+
: action.filename
78+
state[routePath][layer].push(`${filename}#${action.exportedName}`)
79+
}
80+
}
81+
82+
for (const layer of Object.values(state)) {
83+
for (const list of Object.values(layer)) {
84+
list.sort()
85+
}
86+
}
6987

7088
return state
7189
}
Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,39 @@
1-
import { nextTestSetup } from 'e2e-utils'
21
import {
2+
nextTestSetupActionTreeShaking,
33
getActionsRoutesStateByRuntime,
4-
markLayoutAsEdge,
54
} from '../_testing/utils'
65

76
// TODO: revisit when we have a better side-effect free transform approach for server action
87
;(process.env.IS_TURBOPACK_TEST ? describe : describe.skip)(
98
'actions-tree-shaking - basic',
109
() => {
11-
const { next } = nextTestSetup({
10+
const { next } = nextTestSetupActionTreeShaking({
1211
files: __dirname,
1312
})
1413

15-
if (process.env.TEST_EDGE) {
16-
markLayoutAsEdge(next)
17-
}
18-
1914
it('should not have the unused action in the manifest', async () => {
2015
const actionsRoutesState = await getActionsRoutesStateByRuntime(next)
21-
22-
expect(actionsRoutesState).toMatchObject({
23-
// only one server layer action
24-
'app/server/page': {
25-
rsc: 3,
26-
},
27-
// only one browser layer action
28-
'app/client/page': {
29-
'action-browser': 1,
30-
},
31-
'app/inline/page': {
32-
rsc: 1,
33-
},
34-
})
16+
expect(actionsRoutesState).toMatchInlineSnapshot(`
17+
{
18+
"app/client/page": {
19+
"action-browser": [
20+
"app/actions.js#clientComponentAction",
21+
],
22+
},
23+
"app/inline/page": {
24+
"rsc": [
25+
"app/inline/page.js#$$RSC_SERVER_ACTION_0",
26+
],
27+
},
28+
"app/server/page": {
29+
"rsc": [
30+
"app/actions.js#clientComponentAction",
31+
"app/actions.js#serverComponentAction",
32+
"app/actions.js#unusedExportedAction",
33+
],
34+
},
35+
}
36+
`)
3537
})
3638
}
3739
)
Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,36 @@
1-
import { nextTestSetup } from 'e2e-utils'
21
import {
2+
nextTestSetupActionTreeShaking,
33
getActionsRoutesStateByRuntime,
4-
markLayoutAsEdge,
54
} from '../_testing/utils'
65

76
// TODO: revisit when we have a better side-effect free transform approach for server action
87
;(process.env.IS_TURBOPACK_TEST ? describe : describe.skip)(
98
'actions-tree-shaking - mixed-module-actions',
109
() => {
11-
const { next } = nextTestSetup({
10+
const { next } = nextTestSetupActionTreeShaking({
1211
files: __dirname,
1312
})
1413

15-
if (process.env.TEST_EDGE) {
16-
markLayoutAsEdge(next)
17-
}
18-
1914
it('should not do tree shake for cjs module when import server actions', async () => {
2015
const actionsRoutesState = await getActionsRoutesStateByRuntime(next)
21-
22-
expect(actionsRoutesState).toMatchObject({
23-
'app/mixed-module/esm/page': {
24-
rsc: 3,
25-
},
26-
// CJS import is not able to tree shake, so it will include all actions
27-
'app/mixed-module/cjs/page': {
28-
rsc: 3,
29-
},
30-
})
16+
expect(actionsRoutesState).toMatchInlineSnapshot(`
17+
{
18+
"app/mixed-module/cjs/page": {
19+
"rsc": [
20+
"app/mixed-module/cjs/actions.js#cjsModuleTypeAction",
21+
"app/mixed-module/cjs/actions.js#esmModuleTypeAction",
22+
"app/mixed-module/cjs/actions.js#unusedModuleTypeAction1",
23+
],
24+
},
25+
"app/mixed-module/esm/page": {
26+
"rsc": [
27+
"app/mixed-module/esm/actions.js#cjsModuleTypeAction",
28+
"app/mixed-module/esm/actions.js#esmModuleTypeAction",
29+
"app/mixed-module/esm/actions.js#unusedModuleTypeAction1",
30+
],
31+
},
32+
}
33+
`)
3134
})
3235
}
3336
)

test/production/app-dir/actions-tree-shaking/reexport/reexport.test.ts

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,62 @@
1-
import { nextTestSetup } from 'e2e-utils'
21
import {
2+
nextTestSetupActionTreeShaking,
33
getActionsRoutesStateByRuntime,
4-
markLayoutAsEdge,
54
} from '../_testing/utils'
65
import { retry } from 'next-test-utils'
76

87
// TODO: revisit when we have a better side-effect free transform approach for server action
98
;(process.env.IS_TURBOPACK_TEST ? describe : describe.skip)(
109
'actions-tree-shaking - reexport',
1110
() => {
12-
const { next } = nextTestSetup({
11+
const { next } = nextTestSetupActionTreeShaking({
1312
files: __dirname,
1413
skipDeployment: true,
1514
})
1615

17-
if (process.env.TEST_EDGE) {
18-
markLayoutAsEdge(next)
19-
}
20-
2116
it('should not tree-shake namespace exports the manifest', async () => {
2217
const actionsRoutesState = await getActionsRoutesStateByRuntime(next)
2318

24-
expect(actionsRoutesState).toMatchObject({
25-
'app/namespace-reexport/server/page': {
26-
// Turbopack does not tree-shake server side chunks
27-
rsc: process.env.IS_TURBOPACK_TEST ? 3 : 1,
28-
},
29-
'app/namespace-reexport/client/page': {
30-
'action-browser': 1,
31-
},
32-
// We're not able to tree-shake these re-exports here in webpack mode
33-
'app/named-reexport/server/page': {
34-
// Turbopack supports tree-shaking these re-exports
35-
rsc: 3,
36-
},
37-
'app/named-reexport/client/page': {
38-
// Turbopack supports tree-shaking these re-exports
39-
'action-browser': process.env.IS_TURBOPACK_TEST ? 1 : 3,
40-
},
41-
})
19+
expect(actionsRoutesState).toMatchInlineSnapshot(`
20+
{
21+
"app/named-reexport/client/page": {
22+
"action-browser": [
23+
"app/named-reexport/client/actions.js#sharedClientLayerAction",
24+
],
25+
},
26+
"app/named-reexport/server/page": {
27+
"rsc": [
28+
"app/named-reexport/server/actions.js#sharedServerLayerAction",
29+
"app/named-reexport/server/actions.js#unusedServerLayerAction1",
30+
"app/named-reexport/server/actions.js#unusedServerLayerAction2",
31+
],
32+
},
33+
"app/namespace-reexport-2/client/page": {
34+
"action-browser": [
35+
"app/namespace-reexport-2/actions/action-modules.js#action",
36+
"app/namespace-reexport-2/nested.js#getFoo",
37+
],
38+
},
39+
"app/namespace-reexport-2/server/page": {
40+
"rsc": [
41+
"app/namespace-reexport-2/actions/action-modules.js#action",
42+
"app/namespace-reexport-2/nested.js#foo",
43+
"app/namespace-reexport-2/nested.js#getFoo",
44+
],
45+
},
46+
"app/namespace-reexport/client/page": {
47+
"action-browser": [
48+
"app/namespace-reexport/client/actions.js#sharedClientLayerAction",
49+
],
50+
},
51+
"app/namespace-reexport/server/page": {
52+
"rsc": [
53+
"app/namespace-reexport/server/actions.js#sharedServerLayerAction",
54+
"app/namespace-reexport/server/actions.js#unusedServerLayerAction1",
55+
"app/namespace-reexport/server/actions.js#unusedServerLayerAction2",
56+
],
57+
},
58+
}
59+
`)
4260
})
4361

4462
it('should keep all the action exports for namespace export case on client layer', async () => {
Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,46 @@
1-
import { nextTestSetup } from 'e2e-utils'
21
import {
2+
nextTestSetupActionTreeShaking,
33
getActionsRoutesStateByRuntime,
4-
markLayoutAsEdge,
54
} from '../_testing/utils'
65

76
// TODO: revisit when we have a better side-effect free transform approach for server action
87
;(process.env.IS_TURBOPACK_TEST ? describe : describe.skip)(
98
'actions-tree-shaking - shared-module-actions',
109
() => {
11-
const { next } = nextTestSetup({
10+
const { next } = nextTestSetupActionTreeShaking({
1211
files: __dirname,
1312
})
1413

15-
if (process.env.TEST_EDGE) {
16-
markLayoutAsEdge(next)
17-
}
18-
1914
it('should not have the unused action in the manifest', async () => {
2015
const actionsRoutesState = await getActionsRoutesStateByRuntime(next)
21-
22-
expect(actionsRoutesState).toMatchObject({
23-
'app/server/one/page': {
24-
rsc: 3,
25-
},
26-
'app/server/two/page': {
27-
rsc: 3,
28-
},
29-
'app/client/one/page': {
30-
'action-browser': 1,
31-
},
32-
'app/client/two/page': {
33-
'action-browser': 1,
34-
},
35-
})
16+
expect(actionsRoutesState).toMatchInlineSnapshot(`
17+
{
18+
"app/client/one/page": {
19+
"action-browser": [
20+
"app/client/actions.js#sharedClientLayerAction",
21+
],
22+
},
23+
"app/client/two/page": {
24+
"action-browser": [
25+
"app/client/actions.js#sharedClientLayerAction",
26+
],
27+
},
28+
"app/server/one/page": {
29+
"rsc": [
30+
"app/server/actions.js#sharedServerLayerAction",
31+
"app/server/actions.js#unusedServerLayerAction1",
32+
"app/server/actions.js#unusedServerLayerAction2",
33+
],
34+
},
35+
"app/server/two/page": {
36+
"rsc": [
37+
"app/server/actions.js#sharedServerLayerAction",
38+
"app/server/actions.js#unusedServerLayerAction1",
39+
"app/server/actions.js#unusedServerLayerAction2",
40+
],
41+
},
42+
}
43+
`)
3644
})
3745
}
3846
)

0 commit comments

Comments
 (0)