Skip to content

Commit 25ad894

Browse files
test(qwik-nx): check page responses in e2e (#100)
1 parent 9f2a509 commit 25ad894

File tree

8 files changed

+372
-214
lines changed

8 files changed

+372
-214
lines changed

.eslintrc.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,13 @@
4949
"rules": {}
5050
},
5151
{
52-
"files": ["*.spec.ts", "*.spec.tsx", "*.spec.js", "*.spec.jsx"],
52+
"files": [
53+
"*.spec.ts",
54+
"*.spec.tsx",
55+
"*.spec.js",
56+
"*.spec.jsx",
57+
"*.suite.ts"
58+
],
5359
"env": {
5460
"jest": true
5561
},
Lines changed: 161 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import 'isomorphic-fetch';
2+
13
import {
24
checkFilesExist,
35
ensureNxProject,
@@ -11,6 +13,7 @@ import {
1113
killPort,
1214
stripConsoleColors,
1315
killPorts,
16+
DEFAULT_E2E_TIMEOUT,
1417
} from '@qwikifiers/e2e/utils';
1518

1619
export function testApplicationBasicBehavior(generator: 'app' | 'preset') {
@@ -33,7 +36,7 @@ export function testApplicationBasicBehavior(generator: 'app' | 'preset') {
3336
await runNxCommandAsync(
3437
`generate qwik-nx:${generator} ${projectNameParam} --no-interactive`
3538
);
36-
}, 200000);
39+
}, DEFAULT_E2E_TIMEOUT);
3740

3841
afterAll(async () => {
3942
await runNxCommandAsync('reset');
@@ -43,80 +46,164 @@ export function testApplicationBasicBehavior(generator: 'app' | 'preset') {
4346
expect(() => checkFilesExist(`tsconfig.base.json`)).not.toThrow();
4447
});
4548

46-
it('should create qwik-nx', async () => {
47-
const result = await runNxCommandAsync(`build ${project}`);
48-
expect(stripConsoleColors(result.stdout.replace(/\n|\s/g, ''))).toContain(
49-
[
50-
'Targets to be executed:',
51-
`${project}:build.client`,
52-
`${project}:build.ssr`,
53-
]
54-
.join('')
55-
.replace(/\n|\s/g, '')
56-
);
57-
expect(result.stdout).toContain(
58-
`Successfully ran target build for project ${project}`
59-
);
60-
expect(() =>
61-
checkFilesExist(`dist/apps/${project}/client/q-manifest.json`)
62-
).not.toThrow();
63-
expect(() =>
64-
checkFilesExist(`dist/apps/${project}/server/entry.preview.mjs`)
65-
).not.toThrow();
66-
}, 200000);
67-
68-
it('should run build with a specified configuration', async () => {
69-
// TODO: cloudflare pages or custom configurations should also be tested
70-
const result = await runNxCommandAsync(
71-
`build ${project} --configuration=preview`
72-
);
73-
expect(stripConsoleColors(result.stdout.replace(/\n|\s/g, ''))).toContain(
74-
[
75-
'Targets to be executed:',
76-
`${project}:build.client:preview`,
77-
`${project}:build.ssr:preview`,
78-
]
79-
.join('')
80-
.replace(/\n|\s/g, '')
81-
);
82-
expect(result.stdout).toContain(
83-
`Successfully ran target build for project ${project}`
84-
);
85-
}, 200000);
86-
87-
it('should serve application in dev mode with custom port', async () => {
88-
const p = await runCommandUntil(
89-
`run ${project}:serve --port=${devServerPort}`,
90-
(output) => {
91-
return (
92-
output.includes('Local:') && output.includes(`:${devServerPort}`)
93-
);
49+
it(
50+
'should create qwik-nx',
51+
async () => {
52+
const result = await runNxCommandAsync(`build ${project}`);
53+
expect(
54+
stripConsoleColors(result.stdout.replace(/\n|\s/g, ''))
55+
).toContain(
56+
[
57+
'Targets to be executed:',
58+
`${project}:build.client`,
59+
`${project}:build.ssr`,
60+
]
61+
.join('')
62+
.replace(/\n|\s/g, '')
63+
);
64+
expect(result.stdout).toContain(
65+
`Successfully ran target build for project ${project}`
66+
);
67+
expect(() =>
68+
checkFilesExist(`dist/apps/${project}/client/q-manifest.json`)
69+
).not.toThrow();
70+
expect(() =>
71+
checkFilesExist(`dist/apps/${project}/server/entry.preview.mjs`)
72+
).not.toThrow();
73+
},
74+
DEFAULT_E2E_TIMEOUT
75+
);
76+
77+
it(
78+
'should run build with a specified configuration',
79+
async () => {
80+
// TODO: cloudflare pages or custom configurations should also be tested
81+
const result = await runNxCommandAsync(
82+
`build ${project} --configuration=preview`
83+
);
84+
expect(
85+
stripConsoleColors(result.stdout.replace(/\n|\s/g, ''))
86+
).toContain(
87+
[
88+
'Targets to be executed:',
89+
`${project}:build.client:preview`,
90+
`${project}:build.ssr:preview`,
91+
]
92+
.join('')
93+
.replace(/\n|\s/g, '')
94+
);
95+
expect(result.stdout).toContain(
96+
`Successfully ran target build for project ${project}`
97+
);
98+
},
99+
DEFAULT_E2E_TIMEOUT
100+
);
101+
102+
it(
103+
'should serve application in dev mode with custom port',
104+
async () => {
105+
let host: string | undefined;
106+
const p = await runCommandUntil(
107+
`run ${project}:serve --port=${devServerPort}`,
108+
(output) => {
109+
host = getHostOutput(output, devServerPort);
110+
return !!host;
111+
}
112+
);
113+
await checkPageResponses(host!);
114+
try {
115+
await promisifiedTreeKill(p.pid!, 'SIGKILL');
116+
await killPort(devServerPort);
117+
} catch {
118+
// ignore
94119
}
95-
);
96-
try {
97-
await promisifiedTreeKill(p.pid!, 'SIGKILL');
98-
await killPort(devServerPort);
99-
} catch {
100-
// ignore
101-
}
102-
}, 200000);
103-
104-
it('should serve application in preview mode with custom port', async () => {
105-
const p = await runCommandUntil(
106-
`run ${project}:preview --port=${previewServerPort}`,
107-
(output) => {
108-
return (
109-
output.includes('Local:') &&
110-
output.includes(`:${previewServerPort}`)
111-
);
120+
},
121+
DEFAULT_E2E_TIMEOUT
122+
);
123+
124+
it(
125+
'should serve application in preview mode with custom port',
126+
async () => {
127+
let host: string | undefined;
128+
const p = await runCommandUntil(
129+
`run ${project}:preview --port=${previewServerPort}`,
130+
(output) => {
131+
host = getHostOutput(output, previewServerPort);
132+
return !!host;
133+
}
134+
);
135+
await checkPageResponses(host!);
136+
try {
137+
await promisifiedTreeKill(p.pid!, 'SIGKILL');
138+
await killPort(previewServerPort);
139+
} catch {
140+
// ignore
112141
}
113-
);
114-
try {
115-
await promisifiedTreeKill(p.pid!, 'SIGKILL');
116-
await killPort(previewServerPort);
117-
} catch {
118-
// ignore
119-
}
120-
}, 200000);
142+
},
143+
DEFAULT_E2E_TIMEOUT
144+
);
121145
});
122146
}
147+
148+
async function checkPageResponses(host: string) {
149+
// wait for a while to make sure everything is settled
150+
await new Promise(r => setTimeout(r, 3000));
151+
const domParser = new DOMParser();
152+
const pages = ['', 'flower'];
153+
for (const page of pages) {
154+
const url = `${host}/${page}`;
155+
const res = await fetch(url, { headers: { accept: 'text/html' } }).then(
156+
(r) => r.text()
157+
);
158+
const html = domParser.parseFromString(res, 'text/html');
159+
expectHtmlOnAPage(html, page);
160+
}
161+
}
162+
163+
function getHostOutput(output: string, port: number): string | undefined {
164+
// extracts the host url from the output message
165+
// the reason it's done is because it can either be in these formats:
166+
// http://localhost:4200 or https://127.0.0.1:4200
167+
const regexp = new RegExp(
168+
`Local:(?:\\s{3})(http(?:s)?:\\/\\/(?:.+):${port})`
169+
);
170+
return output.match(regexp)?.[1];
171+
}
172+
173+
function expectHtmlOnAPage(html: Document, page: string) {
174+
switch (page) {
175+
case '':
176+
expectHtmlOnARootPage(html);
177+
break;
178+
case 'flower':
179+
expectHtmlOnAFlowerPage(html);
180+
break;
181+
}
182+
}
183+
184+
function expectHtmlOnARootPage(html: Document) {
185+
expectCommonHtml(html);
186+
187+
expect(html.querySelector('.mindblow')?.textContent).toContain(
188+
'Blow my mind'
189+
);
190+
}
191+
192+
function expectHtmlOnAFlowerPage(html: Document) {
193+
expectCommonHtml(html);
194+
195+
expect(html.querySelector('input[type="range"]')).toBeTruthy();
196+
}
197+
198+
function expectCommonHtml(html: Document) {
199+
const headerLinks = html.querySelectorAll('header li a');
200+
expect(headerLinks.length).toBe(3);
201+
expect(Array.from(headerLinks).map((l) => l.textContent)).toEqual([
202+
'Docs',
203+
'Examples',
204+
'Tutorials',
205+
]);
206+
expect(html.querySelector('footer')?.textContent).toContain(
207+
'Made with ♡ by Builder.io'
208+
);
209+
}

e2e/qwik-nx-e2e/tests/chore.spec.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
readJson,
44
runNxCommandAsync,
55
} from '@nrwl/nx-plugin/testing';
6+
import { DEFAULT_E2E_TIMEOUT } from '@qwikifiers/e2e/utils';
67

78
describe('appGenerator e2e', () => {
89
// Setting up individual workspaces per
@@ -22,8 +23,10 @@ describe('appGenerator e2e', () => {
2223
});
2324

2425
describe("qwik-nx's compiled package.json", () => {
25-
it("qwik-nx's package.json should contain only expected dependencies", async () => {
26-
const packageJson = readJson('node_modules/qwik-nx/package.json');
26+
it(
27+
"qwik-nx's package.json should contain only expected dependencies",
28+
async () => {
29+
const packageJson = readJson('node_modules/qwik-nx/package.json');
2730

2831
expect(packageJson.dependencies).toBeUndefined();
2932
expect(packageJson.peerDependencies).toEqual({
@@ -33,6 +36,6 @@ describe('appGenerator e2e', () => {
3336
'@nrwl/vite': '^15.8.0',
3437
tslib: '^2.3.0',
3538
});
36-
}, 200000);
39+
}, DEFAULT_E2E_TIMEOUT);
3740
});
3841
});

0 commit comments

Comments
 (0)