Skip to content

Commit 2689fea

Browse files
chore: add off ci e2e tests for every page landing (#802)
1 parent 070fff7 commit 2689fea

File tree

4 files changed

+278
-5
lines changed

4 files changed

+278
-5
lines changed

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@
1717
"build:report": "trash report && vue-cli-service build",
1818
"test:unit": "vitest",
1919
"test:unit:ci": "node ./node_modules/.bin/vitest ",
20-
"test:play": "npx playwright test --project=chromium",
21-
"test:play:dev": "NODE_OPTIONS='--no-experimental-strip-types' yarn test:play npx playwright test --project=chromium --trace retain-on-first-failure --retries 0",
20+
"test:play": "npx playwright test playwright/ --project=chromium ",
21+
"test:play:dev": "NODE_OPTIONS='--no-experimental-strip-types' npx playwright test playwright/ --project=chromium --trace retain-on-first-failure --retries 0 tests/playwright",
22+
"test:play:landing": "NODE_OPTIONS='--no-experimental-strip-types' npx playwright test landing/ --headed --project=chromium --trace retain-on-first-failure --retries 0",
2223
"test:play:gen": "npx playwright codegen --ignore-https-errors http://localhost:8080",
23-
"test:play:chromium": "npx playwright test --project=chromium",
24+
"test:play:chromium": "npx playwright test playwright/ --project=chromium",
2425
"lint:ci": "yarn run lint:ci:js && yarn run lint:ci:scss && yarn run check-types",
2526
"lint:ci:js": "node ./node_modules/.bin/eslint --ext .js,.vue,.ts src",
2627
"lint:ci:scss": "node ./node_modules/.bin/stylelint -c .stylelintrc.json \"**/*.{vue,scss,sass,css}\" --ignore-path .gitignore",

playwright.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ dotenv.config()
1313
export default defineConfig({
1414
/* Maximum time the whole test suite can run for. */
1515
globalTimeout: 90 * 60 * 1000,
16-
testDir: './tests/playwright',
16+
testDir: './tests',
1717
/* Maximum time one test can run for. */
1818
timeout: 30 * 60 * 1000,
1919
expect: {

src/pages/AdminPortalPageV2/AdminPortalPage.vue

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@ const breadcrumbs = computed(() => [
118118
route: { name: 'Admin' },
119119
},
120120
])
121-
122121
try {
123122
const runtimeConfig = useRuntimeConfig()
124123
const organization = await getOrganizationByCode(runtimeConfig.public.appApiOrgCode)

tests/landing/landing.spec.ts

Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
import { test } from '@playwright/test'
2+
import { usersDict } from '../playwright/variables'
3+
import { logIn } from '../playwright/lib'
4+
import { LogLevel, Logger } from '../playwright/logger'
5+
import { expect } from 'chai'
6+
7+
const groupId = 'clubs'
8+
const categoryId = 'learning-planet-institute'
9+
const instructionId = '50'
10+
const newsId = '57'
11+
const userId = 'playwright-test'
12+
const projectId = 'lpi-projects'
13+
const token = 'abcdef'
14+
15+
// in app.vue,
16+
// console.log(router.getRoutes().map((r) => r.path).sort())
17+
// then regexes applied:
18+
// /"/g --> `
19+
// /:([a-zA-Z]+\??)/g --> ${$1}
20+
// and cleanup variable names
21+
22+
const startedAt = Date.now()
23+
console.log(`Landing tests started at ${new Date(startedAt).toISOString()}`)
24+
25+
const allUrls: Record<string, { logged: boolean; admin: boolean }> = {
26+
[`/`]: { logged: false, admin: false },
27+
//[`/${pathMatch}(.*)*`]: {logged: false, admin: false},
28+
[`/accessibility`]: { logged: false, admin: false },
29+
[`/admin`]: { logged: true, admin: true },
30+
[`/admin/accounts`]: { logged: true, admin: true },
31+
[`/admin/categories`]: { logged: true, admin: true },
32+
[`/admin/faq`]: { logged: true, admin: true },
33+
[`/admin/general`]: { logged: true, admin: true },
34+
[`/admin/groups`]: { logged: true, admin: true },
35+
[`/admin/groups/create`]: { logged: true, admin: true },
36+
[`/admin/groups/edit/${groupId}`]: { logged: true, admin: true },
37+
[`/admin/groups/list`]: { logged: true, admin: true },
38+
[`/admin/links`]: { logged: true, admin: true },
39+
[`/admin/links/create`]: { logged: true, admin: true },
40+
[`/admin/links/list`]: { logged: true, admin: true },
41+
[`/admin/requests`]: { logged: true, admin: true },
42+
[`/admin/settings`]: { logged: true, admin: true },
43+
[`/admin/skills`]: { logged: true, admin: true },
44+
[`/admin/tags`]: { logged: true, admin: true },
45+
[`/admin/templates`]: { logged: true, admin: true },
46+
[`/announcements`]: { logged: false, admin: false },
47+
[`/calendar`]: { logged: false, admin: false },
48+
[`/calendar/future`]: { logged: false, admin: false },
49+
[`/calendar/past`]: { logged: false, admin: false },
50+
[`/categories/`]: { logged: false, admin: false },
51+
[`/category/${categoryId}`]: { logged: false, admin: false },
52+
[`/cookies`]: { logged: false, admin: false },
53+
[`/create-event`]: { logged: true, admin: true },
54+
[`/create-group`]: { logged: true, admin: true },
55+
[`/create-instruction`]: { logged: true, admin: true },
56+
[`/create-news`]: { logged: true, admin: true },
57+
[`/create-project`]: { logged: true, admin: false },
58+
[`/dashboard`]: { logged: false, admin: false },
59+
// [`/debug`]: {logged: false, admin: false},
60+
// [`/debug/icons`]: {logged: false, admin: false},
61+
// [`/debug/onboarding`]: {logged: false, admin: false},
62+
[`/documents`]: { logged: false, admin: false },
63+
[`/group/${groupId}`]: { logged: false, admin: false },
64+
[`/group/${groupId}/Edit`]: { logged: true, admin: true },
65+
[`/group/${groupId}/members`]: { logged: false, admin: false },
66+
[`/group/${groupId}/members/edit`]: { logged: true, admin: true },
67+
[`/group/${groupId}/projects`]: { logged: false, admin: false },
68+
[`/group/${groupId}/projects/edit`]: { logged: true, admin: true },
69+
[`/group/${groupId}/snapshot`]: { logged: false, admin: false },
70+
[`/group/${groupId}/snapshot/edit`]: { logged: true, admin: true },
71+
[`/groups/`]: { logged: false, admin: false },
72+
[`/groups/${groupId}`]: { logged: false, admin: false },
73+
[`/help`]: { logged: false, admin: false },
74+
[`/help/faq`]: { logged: false, admin: false },
75+
[`/help/help`]: { logged: false, admin: false },
76+
[`/help/tutorials`]: { logged: false, admin: false },
77+
[`/instructions`]: { logged: true, admin: false },
78+
[`/instructions/${instructionId}`]: { logged: true, admin: false },
79+
[`/legal-notices`]: { logged: false, admin: false },
80+
[`/login`]: { logged: false, admin: false },
81+
[`/map`]: { logged: false, admin: false },
82+
[`/me`]: { logged: true, admin: false },
83+
// [`/me/*`]: { logged: false, admin: false },
84+
[`/mentorship/respond/${token}`]: { logged: true, admin: false },
85+
[`/news`]: { logged: false, admin: false },
86+
[`/news/${newsId}`]: { logged: false, admin: false },
87+
[`/newsfeed`]: { logged: false, admin: false },
88+
[`/notifications-settings`]: { logged: true, admin: false },
89+
[`/people/`]: { logged: false, admin: false },
90+
[`/personal-data`]: { logged: false, admin: false },
91+
[`/plan-de-continuite-d-action`]: { logged: false, admin: false },
92+
[`/plan-de-securite-des-systemes-d-information`]: { logged: false, admin: false },
93+
[`/portal`]: { logged: false, admin: false },
94+
[`/profile`]: { logged: true, admin: false },
95+
[`/profile/${userId}`]: { logged: false, admin: false },
96+
[`/profile/${userId}/bio`]: { logged: false, admin: false },
97+
[`/profile/${userId}/bio/edit`]: { logged: false, admin: false },
98+
[`/profile/${userId}/general/edit`]: { logged: false, admin: false },
99+
[`/profile/${userId}/groups`]: { logged: false, admin: false },
100+
[`/profile/${userId}/groups/edit`]: { logged: false, admin: false },
101+
[`/profile/${userId}/privacy/edit`]: { logged: false, admin: false },
102+
[`/profile/${userId}/projects`]: { logged: false, admin: false },
103+
[`/profile/${userId}/projects/edit`]: { logged: false, admin: false },
104+
[`/profile/${userId}/skills`]: { logged: false, admin: false },
105+
[`/profile/${userId}/skills/edit`]: { logged: false, admin: false },
106+
[`/profile/${userId}/summary`]: { logged: false, admin: false },
107+
[`/profile/bio`]: { logged: true, admin: false },
108+
[`/profile/bio/edit`]: { logged: true, admin: false },
109+
[`/profile/edit`]: { logged: true, admin: false },
110+
[`/profile/edit/${userId}`]: { logged: true, admin: false },
111+
[`/profile/edit/${userId}/bio`]: { logged: true, admin: false },
112+
[`/profile/edit/${userId}/general`]: { logged: true, admin: false },
113+
[`/profile/edit/${userId}/groups`]: { logged: true, admin: false },
114+
[`/profile/edit/${userId}/privacy`]: { logged: true, admin: false },
115+
[`/profile/edit/${userId}/projects`]: { logged: true, admin: false },
116+
[`/profile/edit/${userId}/skills`]: { logged: true, admin: false },
117+
[`/profile/edit/bio`]: { logged: true, admin: false },
118+
[`/profile/edit/general`]: { logged: true, admin: false },
119+
[`/profile/edit/groups`]: { logged: true, admin: false },
120+
[`/profile/edit/privacy`]: { logged: true, admin: false },
121+
[`/profile/edit/projects`]: { logged: true, admin: false },
122+
[`/profile/edit/skills`]: { logged: true, admin: false },
123+
[`/profile/general/edit`]: { logged: true, admin: false },
124+
[`/profile/groups`]: { logged: false, admin: false },
125+
[`/profile/groups/edit`]: { logged: true, admin: false },
126+
[`/profile/privacy/edit`]: { logged: true, admin: false },
127+
[`/profile/projects`]: { logged: false, admin: false },
128+
[`/profile/projects/edit`]: { logged: true, admin: false },
129+
[`/profile/skills`]: { logged: false, admin: false },
130+
[`/profile/skills/edit`]: { logged: true, admin: false },
131+
[`/profile/summary`]: { logged: false, admin: false },
132+
[`/projects/${projectId}`]: { logged: false, admin: false },
133+
[`/projects/${projectId}/announcements`]: { logged: false, admin: false },
134+
[`/projects/${projectId}/announcements/edit`]: { logged: true, admin: false },
135+
[`/projects/${projectId}/blog-entries`]: { logged: false, admin: false },
136+
[`/projects/${projectId}/blog-entries/edit`]: { logged: true, admin: false },
137+
[`/projects/${projectId}/blogentries`]: { logged: false, admin: false },
138+
[`/projects/${projectId}/comments`]: { logged: false, admin: false },
139+
[`/projects/${projectId}/comments/edit`]: { logged: true, admin: false },
140+
[`/projects/${projectId}/des`]: { logged: false, admin: false },
141+
[`/projects/${projectId}/description`]: { logged: false, admin: false },
142+
[`/projects/${projectId}/description/edit`]: { logged: true, admin: false },
143+
[`/projects/${projectId}/goals`]: { logged: false, admin: false },
144+
[`/projects/${projectId}/goals/edit`]: { logged: true, admin: false },
145+
[`/projects/${projectId}/linked-projects`]: { logged: false, admin: false },
146+
[`/projects/${projectId}/linked-projects/edit`]: { logged: true, admin: false },
147+
[`/projects/${projectId}/locations`]: { logged: false, admin: false },
148+
[`/projects/${projectId}/locations/edit`]: { logged: true, admin: false },
149+
[`/projects/${projectId}/private-exchange`]: { logged: false, admin: false },
150+
[`/projects/${projectId}/private-exchange/edit`]: { logged: true, admin: false },
151+
[`/projects/${projectId}/project-settings`]: { logged: false, admin: false },
152+
[`/projects/${projectId}/project-settings/edit`]: { logged: true, admin: false },
153+
[`/projects/${projectId}/resources`]: { logged: false, admin: false },
154+
[`/projects/${projectId}/resources/edit`]: { logged: true, admin: false },
155+
[`/projects/${projectId}/ressources`]: { logged: false, admin: false },
156+
[`/projects/${projectId}/summary`]: { logged: false, admin: false },
157+
[`/projects/${projectId}/summary/edit`]: { logged: true, admin: false },
158+
[`/projects/${projectId}/team`]: { logged: false, admin: false },
159+
[`/projects/${projectId}/team/edit`]: { logged: true, admin: false },
160+
[`/recommendations/people`]: { logged: false, admin: false },
161+
[`/recommendations/projects`]: { logged: false, admin: false },
162+
[`/register/${token}`]: { logged: false, admin: false },
163+
[`/request-access`]: { logged: false, admin: false },
164+
[`/search`]: { logged: false, admin: false },
165+
[`/search/global`]: { logged: false, admin: false },
166+
[`/search/groups`]: { logged: false, admin: false },
167+
[`/search/people`]: { logged: false, admin: false },
168+
[`/search/projects`]: { logged: false, admin: false },
169+
[`/stats`]: { logged: true, admin: true },
170+
[`/terms-of-service`]: { logged: false, admin: false },
171+
[`/tos`]: { logged: false, admin: false },
172+
}
173+
174+
const logger = new Logger(LogLevel.Debug)
175+
176+
const testPageLanding = async (context, url: string) => {
177+
const pageOne = await context.newPage()
178+
logger.info(`Navigating to ${url}`)
179+
try {
180+
const response = await pageOne.goto(url)
181+
// test status code 200
182+
expect(response.status()).to.be.within(200, 299)
183+
// /login redirects to keycloak, cannot test app load there
184+
if (url !== '/login') {
185+
// test app is mounted
186+
const app = await pageOne.locator('#APP')
187+
// wait for app to be visible
188+
await app.waitFor({ state: 'visible', timeout: 60000 })
189+
const appCount = await app.count()
190+
expect(appCount).to.equal(1)
191+
logger.info(`Successfully landed on ${url}`)
192+
}
193+
} catch (err) {
194+
logger.error(`Failed to land on ${url}`)
195+
logger.error(err)
196+
throw err
197+
}
198+
pageOne.close()
199+
}
200+
201+
test.describe(`landing on pages as anonymous user`, () => {
202+
test.beforeAll(async ({ browser }) => {
203+
/*const pageOne = */ await browser.newPage()
204+
logger.info(`As anonymous user`)
205+
})
206+
for (const [url, options] of Object.entries(allUrls)) {
207+
if (options.logged || options.admin) continue
208+
test(`Landing on ${url} as anonymous`, async ({ context }) => {
209+
await testPageLanding(context, url)
210+
})
211+
}
212+
test.afterAll(async () => {
213+
const finishedAt = Date.now()
214+
console.log(`Anonymous landing tests finished at ${new Date(finishedAt).toISOString()}`)
215+
const duration = finishedAt - startedAt
216+
console.log(`Anonymous landing tests duration: ${(duration / 1000).toFixed(2)} seconds`)
217+
})
218+
})
219+
220+
test.describe(`landing on pages as regular user`, () => {
221+
test.beforeAll(async ({ browser }) => {
222+
const pageOne = await browser.newPage()
223+
logger.info(` User sign in as ${usersDict.playwright.email}`)
224+
try {
225+
await pageOne.goto('/')
226+
await logIn(pageOne, usersDict.playwright)
227+
logger.info('Login successful')
228+
} catch (err) {
229+
logger.error('Login has failed')
230+
logger.error(err)
231+
throw err
232+
}
233+
})
234+
for (const [url, options] of Object.entries(allUrls)) {
235+
if (options.admin) continue
236+
test(`Landing on ${url} as signed in user`, async ({ context }) => {
237+
await testPageLanding(context, url)
238+
})
239+
}
240+
test.afterAll(async () => {
241+
const finishedAt = Date.now()
242+
console.log(`Signedin landing tests finished at ${new Date(finishedAt).toISOString()}`)
243+
const duration = finishedAt - startedAt
244+
console.log(`Signedin landing tests duration: ${(duration / 1000).toFixed(2)} seconds`)
245+
})
246+
})
247+
248+
test.describe(`landing on pages as admin`, () => {
249+
test.beforeAll(async ({ browser }) => {
250+
const pageOne = await browser.newPage()
251+
logger.info(` User sign in as ${usersDict.admin.email}`)
252+
try {
253+
await pageOne.goto('/')
254+
await logIn(pageOne, usersDict.admin)
255+
logger.info('Login successful')
256+
} catch (err) {
257+
logger.error('Login has failed')
258+
logger.error(err)
259+
throw err
260+
}
261+
})
262+
for (const url of Object.keys(allUrls)) {
263+
test(`Landing on ${url} as admin`, async ({ context }) => {
264+
await testPageLanding(context, url)
265+
})
266+
}
267+
test.afterAll(async () => {
268+
const finishedAt = Date.now()
269+
console.log(`Admin landing tests finished at ${new Date(finishedAt).toISOString()}`)
270+
const duration = finishedAt - startedAt
271+
console.log(`Admin landing tests duration: ${(duration / 1000).toFixed(2)} seconds`)
272+
})
273+
})

0 commit comments

Comments
 (0)