forked from chairemobilite/transition
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtestHelpers.ts
More file actions
203 lines (186 loc) · 9 KB
/
Copy pathtestHelpers.ts
File metadata and controls
203 lines (186 loc) · 9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/*
* Copyright 2025, Polytechnique Montreal and contributors
*
* This file is licensed under the MIT License.
* License text available at https://opensource.org/licenses/MIT
*/
import { test, expect, Page, Browser } from '@playwright/test';
// Types for the tests
export type CommonTestParameters = {
context: {
// The main test page
page: Page;
// Store a counter for test names, to avoid duplicate test names. We have many objects to test and they may result in identical test names.
widgetTestCounters: { [testKey: string]: number };
};
};
export type LoginMethods = 'clickLoginButton' | 'enterOnPasswordField' | 'enterOnUsernameField';
type Url = string;
type Title = string;
type LeftMenuSections = 'agencies' | 'nodes' | 'services' | 'scenarios' | 'routing' | 'comparison' | 'accessibilityMap' | 'batchCalculation' | 'gtfsImport' | 'gtfsExport' | 'preferences';
type AvailableLanguages = 'fr' | 'en';
type HasTitleTest = (params: { title: Title } & CommonTestParameters) => void;
type IsLanguageTest = (params: { expectedLanguage: AvailableLanguages } & CommonTestParameters) => void;
type SwitchLanguageTest = (params: { languageToSwitch: AvailableLanguages } & CommonTestParameters) => void;
type HasUrlTest = (params: { expectedUrl: Url } & CommonTestParameters) => void;
type GoToUrlTest = (params: { url: Url } & CommonTestParameters) => void;
type LoginTest = (params: { loginMethod: LoginMethods } & CommonTestParameters) => void;
type LogoutTest = (params: CommonTestParameters) => void;
type LeftMenuTest = (params: { section: LeftMenuSections; expectedRightPanelTitle: string } & CommonTestParameters) => void;
const testUsername = process.env.PLAYWRIGHT_TEST_USER || 'testUser';
const testPassword = process.env.PLAYWRIGHT_TEST_PASSWORD || 'testPassword';
/**
* Open the browser before all the tests and go to the login page
*
* @param {Browser} browser - The test browser object
* @param {Object} options - The options for the test.
* @param {{ [param: string]: string} } options.urlSearchParams - Additional
* parameters to add to the URL as query string question.
* @param {boolean} options.ignoreHTTPSErrors - Whether to ignore HTTPS errors.
* These can happen if running the tests on a remote server with HTTPs (for
* example test instances)
*/
export const initializeTestPage = async (
browser: Browser,
options: { urlSearchParams?: { [param: string]: string }, ignoreHTTPSErrors?: boolean } = {}
): Promise<Page> => {
const context = await browser.newContext({ ignoreHTTPSErrors: options.ignoreHTTPSErrors === true });
const page = await context.newPage();
const baseUrlString = test.info().project.use.baseURL;
if (typeof baseUrlString === 'string' && options.urlSearchParams) {
// Add the search params to the base URL
const baseURL = new URL(baseUrlString);
Object.keys(options.urlSearchParams).forEach((param) => {
baseURL.searchParams.append(param, options.urlSearchParams![param]);
});
await page.goto(baseURL.toString());
} else {
// Go to home page
await page.goto('/');
}
return page;
};
// Close the browser after all the tests
test.afterAll(async ({ browser }) => {
browser.close();
});
const getTestCounter = (context: CommonTestParameters['context'], testKey: string) => {
const testIdx = context.widgetTestCounters[testKey] || 0;
context.widgetTestCounters[testKey] = testIdx + 1;
return context.widgetTestCounters[testKey];
};
/**
* Test that the current page has a specific title.
* @param {Object} options - The options for the test.
* @param {string} options.title - The title of the page.
*/
export const hasTitleTest: HasTitleTest = ({ context, title }) => {
test(`Has title ${title} - ${getTestCounter(context, `${title}`)}`, async () => {
await expect(context.page).toHaveTitle(title);
});
};
/**
* Test that the current page has a specific url.
* @param {Object} options - The options for the test.
* @param {string} options.expectedUrl - The url of the page.
*/
export const hasUrlTest: HasUrlTest = ({ context, expectedUrl }) => {
test(`Current page has the url ${expectedUrl} - ${getTestCounter(context, `${expectedUrl}`)}`, async () => {
await expect(context.page).toHaveURL(expectedUrl);
});
};
/**
* Navigate the current page to a specific URL (path relative to the base URL).
* @param {Object} options - The options for the test.
* @param {string} options.url - The URL (path) to navigate to.
*/
export const goToUrlTest: GoToUrlTest = ({ context, url }) => {
test(`Navigate to ${url} - ${getTestCounter(context, `goto-${url}`)}`, async () => {
await context.page.goto(url);
});
};
/**
* Test that the language is what we expect.
* @param {Object} options - The options for the test.
* @param {string} options.expectedLanguage - The language we expect. Can be either 'en' or 'fr'.
*/
export const isLanguageTest: IsLanguageTest = ({ context, expectedLanguage }) => {
test(`The page is in ${expectedLanguage === 'fr' ? 'French' : 'English'} - ${getTestCounter(context, `${expectedLanguage}`)}`, async () => {
const language = context.page.locator('//html');
await expect(language).toHaveAttribute('lang', expectedLanguage);
const languageButton = context.page.getByRole('button', { name: (expectedLanguage === 'fr' ? 'English' : 'Français') });
await expect(languageButton).toBeVisible();
});
};
/**
* Switch to a language by clicking the button in the top right.
* @param {Object} options - The options for the test.
* @param {string} options.languageToSwitch - The language to switch to. Can be either 'en' or 'fr'.
*/
export const switchLanguageTest: SwitchLanguageTest = ({ context, languageToSwitch }) => {
test(`Switch to the other language (${languageToSwitch === 'fr' ? 'French' : 'English'}) - ${getTestCounter(context, `${languageToSwitch}`)}`, async () => {
const languageButton = context.page.getByRole('button', { name: (languageToSwitch === 'fr' ? 'Français' : 'English') });
await languageButton.click();
});
};
/**
* Login to the test account, and verify we end up on the right page.
* @param {Object} options - The options for the test.
* @param {LoginMethods} options.loginMethod - The method used to log in. By default, presses the login button.
*/
export const loginTest: LoginTest = ({ context, loginMethod }) => {
test(`Login to the test account with method ${loginMethod} - ${getTestCounter(context, `${loginMethod}`)}`, async () => {
const userNameField = context.page.locator('id=usernameOrEmail');
await userNameField.fill(testUsername);
const passwordField = context.page.locator('id=password');
await passwordField.fill(testPassword);
switch(loginMethod) {
case 'clickLoginButton': {
const loginButton = context.page.getByRole('button', { name: 'Login' });
await loginButton.click();
break;
}
case 'enterOnUsernameField': {
await userNameField.click();
await context.page.keyboard.press('Enter');
break;
}
case 'enterOnPasswordField': {
await passwordField.click();
await context.page.keyboard.press('Enter');
break;
}
}
const logoutButton = context.page.getByRole('button', { name: 'Logout' });
await expect(logoutButton).toBeVisible();
const userButton = context.page.getByRole('button', { name: testUsername });
await expect(userButton).toBeVisible();
});
};
/**
* Logout, and verify we end up back on the login page.
* @param {Object} options - The options for the test.
*/
export const logoutTest: LogoutTest = ({ context }) => {
test(`Logout from survey - ${getTestCounter(context, '')}`, async () => {
const logoutButton = context.page.getByRole('button', { name: 'Logout' });
await logoutButton.click();
await expect(context.page).toHaveURL('/login');
});
};
/**
* Click on one of the sections on the left menu, and check that the right panel is the correct one.
* @param {Object} options - The options for the test.
* @param {string} options.section - The section we click.
* @param {string} options.expectedRightPanelTitle - The expected title of the right panel.
*/
export const clickLeftMenuTest: LeftMenuTest = ({ context, section, expectedRightPanelTitle }) => {
test(`Click the ${section} section of the left menu - ${getTestCounter(context, `${section}`)}`, async () => {
const leftMenu = context.page.locator('//nav[@id="tr__left-menu"]/ul[@class="tr__left-menu-container"]');
const sectionButton = leftMenu.locator(`//li/button[@data-section='${section}']/span/img`);
await sectionButton.click();
const rightPanel = context.page.locator('//section[@id="tr__right-panel"]/div[@class="tr__right-panel-inner"]');
const rightPanelTitle = rightPanel.getByRole('heading').nth(0);
await expect(rightPanelTitle).toContainText(expectedRightPanelTitle);
});
};