@appsemble/e2e 0.35.11-test.4 → 0.35.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +25 -14
  2. package/fixtures/index.d.ts +2 -2
  3. package/fixtures/index.js +2 -2
  4. package/fixtures/test/app/index.js +1 -14
  5. package/fixtures/test/app-collection/index.js +1 -11
  6. package/fixtures/test/index.d.ts +12 -1
  7. package/fixtures/test/index.js +52 -2
  8. package/fixtures/test/live-app/index.js +0 -3
  9. package/fixtures/test/organization/index.js +1 -8
  10. package/fixtures/test/resource/index.js +1 -8
  11. package/fixtures/test/training/index.js +2 -10
  12. package/index.d.ts +2 -2
  13. package/index.js +2 -2
  14. package/package.json +7 -7
  15. package/playwright.config.js +19 -11
  16. package/setup/create-accounts.setup.js +11 -0
  17. package/setup/teardown-accounts.setup.d.ts +1 -0
  18. package/setup/teardown-accounts.setup.js +11 -0
  19. package/tests/demo-apps/empty.spec.js +1 -1
  20. package/tests/demo-apps/holidays.spec.js +1 -1
  21. package/tests/demo-apps/notes.spec.js +1 -1
  22. package/tests/demo-apps/person.spec.js +1 -1
  23. package/tests/static-ui/apps.spec.js +10 -5
  24. package/tests/static-ui/blocks.spec.js +1 -1
  25. package/tests/static-ui/docs.spec.js +1 -1
  26. package/tests/static-ui/individual-app.spec.js +8 -5
  27. package/tests/static-ui/organizations.spec.js +1 -1
  28. package/tests/static-ui/training.spec.js +1 -1
  29. package/tests/studio/app-collections/app-collections.spec.js +1 -1
  30. package/tests/studio/individual-app.spec.js +1 -1
  31. package/tests/studio/logins/appsemble.spec.js +1 -1
  32. package/tests/studio/logins/demo.spec.js +1 -1
  33. package/tests/studio/logins/invite.spec.js +1 -1
  34. package/tests/studio/logins/oauth2.spec.js +1 -1
  35. package/tests/studio/logins/password.spec.js +1 -1
  36. package/tests/studio/logins/register.spec.js +1 -1
  37. package/tests/studio/logins/saml.spec.js +1 -1
  38. package/tests/studio/organizations.spec.js +1 -1
  39. package/tests/studio/payments/subscription-flow.spec.js +25 -14
  40. package/tests/studio/root.spec.js +1 -1
  41. package/tests/studio/trainings.spec.js +1 -3
  42. package/setup/auth.setup.js +0 -10
  43. /package/setup/{auth.setup.d.ts → create-accounts.setup.d.ts} +0 -0
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # ![](https://gitlab.com/appsemble/appsemble/-/raw/0.35.11-test.4/config/assets/logo.svg) Appsemble End 2 End Tests
1
+ # ![](https://gitlab.com/appsemble/appsemble/-/raw/0.35.14/config/assets/logo.svg) Appsemble End 2 End Tests
2
2
 
3
3
  > Run end 2 end tests on an Appsemble environment and provide Appsemble fixtures
4
4
 
5
- [![GitLab CI](https://gitlab.com/appsemble/appsemble/badges/0.35.11-test.4/pipeline.svg)](https://gitlab.com/appsemble/appsemble/-/releases/0.35.11-test.4)
5
+ [![GitLab CI](https://gitlab.com/appsemble/appsemble/badges/0.35.14/pipeline.svg)](https://gitlab.com/appsemble/appsemble/-/releases/0.35.14)
6
6
  [![Prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://prettier.io)
7
7
 
8
8
  ## Table of Contents
@@ -38,6 +38,15 @@ test('should navigate to app', async ({ visitApp }) => {
38
38
  });
39
39
  ```
40
40
 
41
+ ## Development
42
+
43
+ This package depends on other packages in the Appsemble monorepo. To make sure all tests run
44
+ normally, go to each Appsemble dependency and run the following command:
45
+
46
+ ```sh
47
+ npm run prepack
48
+ ```
49
+
41
50
  ## Appsemble end-to-end tests
42
51
 
43
52
  To run end to end tests, run:
@@ -58,9 +67,6 @@ during the test as if you ran it using `ui mode`.
58
67
 
59
68
  The end to end tests use the following environment variables:
60
69
 
61
- - `BOT_ACCOUNT_EMAIL` — The email address used to login.
62
- - `BOT_ACCOUNT_PASSWORD` — The password used to login.
63
- - `ACCESS_TOKEN` — The access token of the account that's logged in.
64
70
  - `CI` — Whether the tests are run in CI.
65
71
  - `CI_MERGE_REQUEST_IID` — The id of the merge request if it's present.
66
72
  - `APPSEMBLE_REVIEW_DOMAIN` — The review appsemble domain to use.
@@ -71,16 +77,21 @@ are used.
71
77
 
72
78
  ## Authentication
73
79
 
74
- Some fixtures call the Appsemble API using the Playwright `request` object. This expects you to have
75
- set an access token as environment variable with the name **ACCESS_TOKEN** beforehand. The easiest
76
- way to do this is by setting it in a setup step using the `loginUser` fixture.
77
-
78
- `auth.setup.ts`
80
+ Some fixtures call the Appsemble API using the Playwright `request` object. This expects the worker
81
+ to have logged in and set the access token in the `request` fixture beforehand. This can look like
82
+ so:
79
83
 
80
84
  ```ts
81
- setup('authenticate', async ({ loginUser }) => {
82
- const accessToken = await loginUser('bot', '12345');
83
- process.env.ACCESS_TOKEN = accessToken;
85
+ export const test = base.extend<{}>({
86
+ async request({}, use) {
87
+ const newRequest = await request.newContext({
88
+ extraHTTPHeaders: {
89
+ Authorization: `Bearer ${accessToken}`,
90
+ },
91
+ });
92
+ await use(newRequest);
93
+ await newRequest.dispose();
94
+ },
84
95
  });
85
96
  ```
86
97
 
@@ -91,5 +102,5 @@ When writing end-to-end tests, have a look at the
91
102
 
92
103
  ## License
93
104
 
94
- [LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.35.11-test.4/LICENSE.md) ©
105
+ [LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.35.14/LICENSE.md) ©
95
106
  [Appsemble](https://appsemble.com)
@@ -1,2 +1,2 @@
1
- export { expect } from './expect/index.js';
2
- export { test } from './test/index.js';
1
+ export * from './expect/index.js';
2
+ export * from './test/index.js';
package/fixtures/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { expect } from './expect/index.js';
2
- export { test } from './test/index.js';
1
+ export * from './expect/index.js';
2
+ export * from './test/index.js';
3
3
  //# sourceMappingURL=index.js.map
@@ -18,9 +18,6 @@ export const test = base.extend({
18
18
  }
19
19
  const response = await request.post('/api/apps', {
20
20
  multipart: formData,
21
- headers: {
22
- Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
23
- },
24
21
  });
25
22
  expect(response.status()).toBe(201);
26
23
  const app = (await response.json());
@@ -41,9 +38,6 @@ export const test = base.extend({
41
38
  }
42
39
  const response = await request.patch(`/api/apps/${appId}`, {
43
40
  multipart: formData,
44
- headers: {
45
- Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
46
- },
47
41
  });
48
42
  expect(response.status()).toBe(200);
49
43
  const app = (await response.json());
@@ -53,11 +47,7 @@ export const test = base.extend({
53
47
  },
54
48
  async deleteApp({ request }, use) {
55
49
  await use(async (appId) => {
56
- const response = await request.delete(`/api/apps/${appId}`, {
57
- headers: {
58
- Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
59
- },
60
- });
50
+ const response = await request.delete(`/api/apps/${appId}`);
61
51
  expect(response.status()).toBe(204);
62
52
  });
63
53
  },
@@ -86,9 +76,6 @@ export const test = base.extend({
86
76
  };
87
77
  const response = await request.post(`/api/apps/${appId}/messages`, {
88
78
  data: appMessages,
89
- headers: {
90
- Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
91
- },
92
79
  });
93
80
  expect(response.status()).toBe(201);
94
81
  return (await response.json());
@@ -20,9 +20,6 @@ export const test = base.extend({
20
20
  }
21
21
  const response = await request.post(`/api/organizations/${organizationId}/app-collections`, {
22
22
  multipart: formData,
23
- headers: {
24
- Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
25
- },
26
23
  });
27
24
  expect(response.status()).toBe(201);
28
25
  const appCollection = (await response.json());
@@ -31,11 +28,7 @@ export const test = base.extend({
31
28
  },
32
29
  async deleteAppCollection({ request }, use) {
33
30
  await use(async (collectionId) => {
34
- const response = await request.delete(`/api/app-collections/${collectionId}`, {
35
- headers: {
36
- Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
37
- },
38
- });
31
+ const response = await request.delete(`/api/app-collections/${collectionId}`);
39
32
  expect(response.status()).toBe(204);
40
33
  });
41
34
  },
@@ -45,9 +38,6 @@ export const test = base.extend({
45
38
  data: {
46
39
  AppId: appId,
47
40
  },
48
- headers: {
49
- Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
50
- },
51
41
  });
52
42
  expect(response.status()).toBe(204);
53
43
  });
@@ -1 +1,12 @@
1
- export declare const test: import("@playwright/test").TestType<import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions & import("./app/index.js").AppFixtures & import("./app-collection/index.js").AppCollectionFixtures & import("./demo-app/index.js").DemoAppFixtures & import("./group/index.js").GroupFixtures & import("./live-app/index.js").LiveAppFixtures & import("./organization/index.js").OrganizationFixtures & import("./resource/index.js").ResourceFixtures & import("./studio/index.js").StudioFixtures & import("./test-utils/index.js").TestUtilsFixtures & import("./training/index.js").TrainingFixtures, import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions>;
1
+ /**
2
+ * Base test object with all utility fixtures
3
+ */
4
+ export declare const baseTest: import("@playwright/test").TestType<import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions & import("./app/index.js").AppFixtures & import("./app-collection/index.js").AppCollectionFixtures & import("./demo-app/index.js").DemoAppFixtures & import("./group/index.js").GroupFixtures & import("./live-app/index.js").LiveAppFixtures & import("./organization/index.js").OrganizationFixtures & import("./resource/index.js").ResourceFixtures & import("./studio/index.js").StudioFixtures & import("./test-utils/index.js").TestUtilsFixtures & import("./training/index.js").TrainingFixtures, import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions>;
5
+ /**
6
+ * Test object with the worker's storage state saved
7
+ *
8
+ * Used for tests that require a logged in user
9
+ */
10
+ export declare const authenticatedTest: import("@playwright/test").TestType<import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions & import("./app/index.js").AppFixtures & import("./app-collection/index.js").AppCollectionFixtures & import("./demo-app/index.js").DemoAppFixtures & import("./group/index.js").GroupFixtures & import("./live-app/index.js").LiveAppFixtures & import("./organization/index.js").OrganizationFixtures & import("./resource/index.js").ResourceFixtures & import("./studio/index.js").StudioFixtures & import("./test-utils/index.js").TestUtilsFixtures & import("./training/index.js").TrainingFixtures, import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions & {
11
+ workerStorageState: string;
12
+ }>;
@@ -1,4 +1,7 @@
1
- import { mergeTests } from '@playwright/test';
1
+ import { existsSync } from 'node:fs';
2
+ import { readFile } from 'node:fs/promises';
3
+ import { resolve } from 'node:path';
4
+ import { expect, mergeTests, request } from '@playwright/test';
2
5
  import { test as appFixtures } from './app/index.js';
3
6
  import { test as appCollectionFixtures } from './app-collection/index.js';
4
7
  import { test as demoAppFixtures } from './demo-app/index.js';
@@ -9,5 +12,52 @@ import { test as resourceFixtures } from './resource/index.js';
9
12
  import { test as studioFixtures } from './studio/index.js';
10
13
  import { test as testUtilsFixtures } from './test-utils/index.js';
11
14
  import { test as trainingFixtures } from './training/index.js';
12
- export const test = mergeTests(appFixtures, appCollectionFixtures, demoAppFixtures, groupFixtures, liveAppFixtures, organizationFixtures, resourceFixtures, studioFixtures, testUtilsFixtures, trainingFixtures);
15
+ /**
16
+ * Base test object with all utility fixtures
17
+ */
18
+ export const baseTest = mergeTests(appFixtures, appCollectionFixtures, demoAppFixtures, groupFixtures, liveAppFixtures, organizationFixtures, resourceFixtures, studioFixtures, testUtilsFixtures, trainingFixtures);
19
+ /**
20
+ * Test object with the worker's storage state saved
21
+ *
22
+ * Used for tests that require a logged in user
23
+ */
24
+ export const authenticatedTest = baseTest.extend({
25
+ // Use the same storage state for all tests in this worker.
26
+ storageState: ({ workerStorageState }, use) => use(workerStorageState),
27
+ workerStorageState: [
28
+ async ({ browser }, use, testInfo) => {
29
+ const id = `worker-${testInfo.parallelIndex}`;
30
+ const email = `${id}@appsemble.com`;
31
+ const password = id;
32
+ const fileName = resolve(testInfo.project.outputDir, `.auth/${id}.json`);
33
+ if (existsSync(fileName)) {
34
+ await use(fileName);
35
+ return;
36
+ }
37
+ const page = await browser.newPage({ storageState: undefined });
38
+ await page.goto(`${testInfo.project.use.baseURL}/en/login`);
39
+ await page.getByTestId('email').fill(email);
40
+ await page.getByTestId('password').fill(password);
41
+ await page.getByTestId('login').click();
42
+ // Wait until auth state is saved in browser storage
43
+ await expect(page.getByText('My Apps')).toBeVisible();
44
+ await page.context().storageState({ path: fileName });
45
+ await page.close();
46
+ await use(fileName);
47
+ },
48
+ { scope: 'worker' },
49
+ ],
50
+ async request({ baseURL, storageState }, use) {
51
+ const accessToken = JSON.parse(await readFile(String(storageState), 'utf8')).origins[0]
52
+ .localStorage[1].value;
53
+ const newRequest = await request.newContext({
54
+ baseURL,
55
+ extraHTTPHeaders: {
56
+ Authorization: `Bearer ${accessToken}`,
57
+ },
58
+ });
59
+ await use(newRequest);
60
+ await newRequest.dispose();
61
+ },
62
+ });
13
63
  //# sourceMappingURL=index.js.map
@@ -45,9 +45,6 @@ export const test = base.extend({
45
45
  redirectUri: url,
46
46
  scope: 'openid',
47
47
  },
48
- headers: {
49
- Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
50
- },
51
48
  });
52
49
  expect(response.status()).toBe(201);
53
50
  });
@@ -13,9 +13,6 @@ export const test = base.extend({
13
13
  formData.set('icon', icon ?? null);
14
14
  const response = await request.post('/api/organizations', {
15
15
  multipart: formData,
16
- headers: {
17
- Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
18
- },
19
16
  });
20
17
  expect(response.status()).toBe(201);
21
18
  return response.json();
@@ -23,11 +20,7 @@ export const test = base.extend({
23
20
  },
24
21
  async deleteOrganization({ request }, use) {
25
22
  await use(async (id) => {
26
- const response = await request.delete(`/api/organizations/${id}`, {
27
- headers: {
28
- Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
29
- },
30
- });
23
+ const response = await request.delete(`/api/organizations/${id}`);
31
24
  expect(response.status()).toBe(200);
32
25
  });
33
26
  },
@@ -12,9 +12,6 @@ export const test = base.extend({
12
12
  }
13
13
  const response = await request.post(`/api/apps/${appId}/resources/${type}`, {
14
14
  multipart: formData,
15
- headers: {
16
- Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
17
- },
18
15
  });
19
16
  expect(response.status()).toBe(201);
20
17
  const resource = (await response.json());
@@ -24,11 +21,7 @@ export const test = base.extend({
24
21
  },
25
22
  async deleteAllResources({ request }, use) {
26
23
  await use(async (appId) => {
27
- const response = await request.delete(`/api/apps/${appId}/resources`, {
28
- headers: {
29
- Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
30
- },
31
- });
24
+ const response = await request.delete(`/api/apps/${appId}/resources`);
32
25
  expect(response.status()).toBe(204);
33
26
  });
34
27
  },
@@ -2,21 +2,13 @@ import { test as base, expect } from '@playwright/test';
2
2
  export const test = base.extend({
3
3
  async resetTrainingProgress({ request }, use) {
4
4
  await use(async () => {
5
- const response = await request.delete('/api/trainings/completed', {
6
- headers: {
7
- Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
8
- },
9
- });
5
+ const response = await request.delete('/api/trainings/completed');
10
6
  expect(response.status()).toBe(204);
11
7
  });
12
8
  },
13
9
  async completeTraining({ request }, use) {
14
10
  await use(async (trainingId) => {
15
- const response = await request.post(`/api/trainings/completed/${trainingId}`, {
16
- headers: {
17
- Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
18
- },
19
- });
11
+ const response = await request.post(`/api/trainings/completed/${trainingId}`);
20
12
  expect(response.status()).toBe(201);
21
13
  });
22
14
  },
package/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { test } from './fixtures/test/index.js';
2
- export { expect } from './fixtures/expect/index.js';
1
+ export * from './fixtures/expect/index.js';
2
+ export * from './fixtures/test/index.js';
package/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { test } from './fixtures/test/index.js';
2
- export { expect } from './fixtures/expect/index.js';
1
+ export * from './fixtures/expect/index.js';
2
+ export * from './fixtures/test/index.js';
3
3
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appsemble/e2e",
3
- "version": "0.35.11-test.4",
3
+ "version": "0.35.14",
4
4
  "description": "End-to-end tests used for testing Appsemble apps in an existing environment.",
5
5
  "keywords": [
6
6
  "app",
@@ -38,16 +38,16 @@
38
38
  "test": "vitest"
39
39
  },
40
40
  "dependencies": {
41
- "@appsemble/utils": "0.35.11-test.4",
42
- "@appsemble/types": "0.35.11-test.4",
43
- "@appsemble/lang-sdk": "0.35.11-test.4",
44
- "jwt-decode": "^4.0.0",
45
- "@fortawesome/fontawesome-free": "^6.0.0",
41
+ "@appsemble/lang-sdk": "0.35.14",
42
+ "@appsemble/node-utils": "0.35.14",
43
+ "@appsemble/types": "0.35.14",
46
44
  "@playwright/test": "1.51.1",
47
- "bulma": "=0.9.3",
48
45
  "strip-indent": "^4.0.0"
49
46
  },
50
47
  "engines": {
51
48
  "node": ">=20"
49
+ },
50
+ "devDependencies": {
51
+ "eslint-plugin-playwright": "2.2.2"
52
52
  }
53
53
  }
@@ -5,14 +5,14 @@ const { APPSEMBLE_REVIEW_DOMAIN, APPSEMBLE_STAGING_DOMAIN, CI, CI_MERGE_REQUEST_
5
5
  */
6
6
  export default defineConfig({
7
7
  testMatch: '**/*.spec.ts',
8
- // Tests aren't fully isolated so they shouldn't run in parallel
9
- fullyParallel: false,
8
+ // Run tests in parallel
9
+ fullyParallel: true,
10
10
  // Fail the build on CI if you accidentally left test.only in the source code.
11
11
  forbidOnly: Boolean(CI),
12
12
  // Retry on CI only
13
13
  retries: CI ? 2 : 0,
14
- // Concurrent tests run better on CI in general
15
- workers: 1,
14
+ // Amount of workers to run tests with
15
+ workers: CI ? 2 : 1,
16
16
  // Reporter to use. See https://playwright.dev/docs/test-reporters
17
17
  reporter: [['junit', { outputFile: 'results.xml' }]],
18
18
  // Prevent the pipeline from timing out
@@ -50,22 +50,30 @@ export default defineConfig({
50
50
  use: { ...devices['Desktop Safari'] },
51
51
  fullyParallel: true,
52
52
  },
53
- { name: 'setup', testMatch: /.*\.setup\.ts/ },
53
+ {
54
+ name: 'create-accounts',
55
+ testMatch: /create-accounts\.setup\.ts/,
56
+ teardown: 'teardown-accounts',
57
+ },
54
58
  {
55
59
  name: 'chromium',
56
- use: { ...devices['Desktop Chrome'], storageState: '.auth/user.json' },
57
- dependencies: ['setup'],
60
+ testIgnore: '**/static-ui/**',
61
+ use: { ...devices['Desktop Chrome'] },
62
+ dependencies: ['create-accounts'],
58
63
  },
59
64
  {
60
65
  name: 'firefox',
61
- use: { ...devices['Desktop Firefox'], storageState: '.auth/user.json' },
62
- dependencies: ['setup'],
66
+ testIgnore: '**/static-ui/**',
67
+ use: { ...devices['Desktop Firefox'] },
68
+ dependencies: ['create-accounts'],
63
69
  },
64
70
  {
65
71
  name: 'webkit',
66
- use: { ...devices['Desktop Safari'], storageState: '.auth/user.json' },
67
- dependencies: ['setup'],
72
+ testIgnore: '**/static-ui/**',
73
+ use: { ...devices['Desktop Safari'] },
74
+ dependencies: ['create-accounts'],
68
75
  },
76
+ { name: 'teardown-accounts', testMatch: /teardown-accounts\.setup\.ts/ },
69
77
  ],
70
78
  });
71
79
  //# sourceMappingURL=playwright.config.js.map
@@ -0,0 +1,11 @@
1
+ import { createUser } from '@appsemble/node-utils';
2
+ import { test as setup } from '@playwright/test';
3
+ setup('create accounts for workers', async ({}, testInfo) => {
4
+ for (let i = 0; i < testInfo.config.workers; i += 1) {
5
+ const id = `worker-${i}`;
6
+ const email = `${id}@appsemble.com`;
7
+ const password = id;
8
+ await createUser(id, email, password);
9
+ }
10
+ });
11
+ //# sourceMappingURL=create-accounts.setup.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ import { rm } from 'node:fs/promises';
2
+ import { deleteUser } from '@appsemble/node-utils';
3
+ import { test as setup } from '@playwright/test';
4
+ setup('delete worker accounts', async ({}, testInfo) => {
5
+ for (let i = 0; i < testInfo.config.workers; i += 1) {
6
+ const email = `worker-${i}@appsemble.com`;
7
+ await deleteUser(email);
8
+ }
9
+ await rm(`${testInfo.project.outputDir}/.auth`, { recursive: true, force: true });
10
+ });
11
+ //# sourceMappingURL=teardown-accounts.setup.js.map
@@ -1,5 +1,5 @@
1
1
  import { readFile } from 'node:fs/promises';
2
- import { expect, test } from '../../index.js';
2
+ import { expect, authenticatedTest as test } from '../../index.js';
3
3
  let appId;
4
4
  let organizationId;
5
5
  test.describe('Empty', () => {
@@ -1,5 +1,5 @@
1
1
  import { readFile } from 'node:fs/promises';
2
- import { expect, test } from '../../index.js';
2
+ import { expect, authenticatedTest as test } from '../../index.js';
3
3
  let appId;
4
4
  let organizationId;
5
5
  test.describe('Holidays', () => {
@@ -1,5 +1,5 @@
1
1
  import { readFile } from 'node:fs/promises';
2
- import { expect, test } from '../../index.js';
2
+ import { expect, authenticatedTest as test } from '../../index.js';
3
3
  let appId;
4
4
  let organizationId;
5
5
  test.describe('Notes', () => {
@@ -1,5 +1,5 @@
1
1
  import { readFile } from 'node:fs/promises';
2
- import { expect, test } from '../../index.js';
2
+ import { expect, authenticatedTest as test } from '../../index.js';
3
3
  let appId;
4
4
  let organizationId;
5
5
  test.describe('Person', () => {
@@ -1,5 +1,5 @@
1
- import { expect, test } from '../../index.js';
2
- const { BOT_ACCOUNT_EMAIL, BOT_ACCOUNT_PASSWORD } = process.env;
1
+ import { createUser, deleteUser } from '@appsemble/node-utils';
2
+ import { expect, baseTest as test } from '../../index.js';
3
3
  test.describe('Apps', () => {
4
4
  // Prevent worker from being logged in automatically
5
5
  test.use({ storageState: { cookies: [], origins: [] } });
@@ -15,10 +15,15 @@ test.describe('Apps', () => {
15
15
  test('should show the page header', async ({ page }) => {
16
16
  await expect(page.getByRole('heading', { name: 'All Apps', exact: true })).toBeVisible();
17
17
  });
18
- test('should display “My Apps” when logged in', async ({ loginUser, page }) => {
19
- expect(BOT_ACCOUNT_EMAIL && BOT_ACCOUNT_PASSWORD).not.toBeUndefined();
20
- await loginUser(BOT_ACCOUNT_EMAIL, BOT_ACCOUNT_PASSWORD);
18
+ test('should display “My Apps” when logged in', async ({ browser, loginUserOnPage, randomTestId, }) => {
19
+ const name = 'Test user';
20
+ const email = `${randomTestId()}@test.com`;
21
+ const password = '1';
22
+ await createUser(name, email, password);
23
+ const page = await browser.newPage({ storageState: undefined });
24
+ await loginUserOnPage(email, password, page);
21
25
  await expect(page.getByRole('heading', { name: 'My Apps', exact: true })).toBeVisible();
26
+ await deleteUser(email);
22
27
  });
23
28
  test('should render list of apps', async ({ page }) => {
24
29
  await expect(page.getByRole('link', { name: 'Test app Test org' }).first())
@@ -1,4 +1,4 @@
1
- import { expect, test } from '../../index.js';
1
+ import { expect, baseTest as test } from '../../index.js';
2
2
  test.describe('Blocks', () => {
3
3
  test.beforeEach(async ({ page }) => {
4
4
  await page.route('**/api/blocks', async (route) => {
@@ -1,6 +1,6 @@
1
1
  import { AppPermission, predefinedAppRoles } from '@appsemble/lang-sdk';
2
2
  import { OrganizationPermission, predefinedOrganizationRoles } from '@appsemble/types';
3
- import { expect, test } from '../../index.js';
3
+ import { expect, baseTest as test } from '../../index.js';
4
4
  test.describe('Docs', () => {
5
5
  test('should render the index page', async ({ page }) => {
6
6
  await page.goto('/en/docs');
@@ -1,11 +1,14 @@
1
- import { expect, test } from '../../index.js';
2
- const { BOT_ACCOUNT_EMAIL, BOT_ACCOUNT_PASSWORD } = process.env;
1
+ import { createUser } from '@appsemble/node-utils';
2
+ import { expect, baseTest as test } from '../../index.js';
3
3
  let page;
4
4
  test.describe('Individual app', () => {
5
- test.beforeAll(async ({ browser, loginUserOnPage }) => {
5
+ test.beforeAll(async ({ browser, loginUserOnPage, randomTestId }) => {
6
+ const name = 'Test user';
7
+ const email = `${randomTestId()}@test.com`;
8
+ const password = '1';
9
+ await createUser(name, email, password);
6
10
  page = await browser.newPage({ storageState: undefined });
7
- expect(BOT_ACCOUNT_EMAIL && BOT_ACCOUNT_PASSWORD).not.toBeUndefined();
8
- await loginUserOnPage(BOT_ACCOUNT_EMAIL, BOT_ACCOUNT_PASSWORD, page);
11
+ await loginUserOnPage(email, password, page);
9
12
  });
10
13
  test.afterAll(async () => {
11
14
  await page.close();
@@ -1,4 +1,4 @@
1
- import { expect, test } from '../../index.js';
1
+ import { expect, baseTest as test } from '../../index.js';
2
2
  test.describe('Organizations', () => {
3
3
  test.beforeEach(async ({ page }) => {
4
4
  await page.route('**/api/organizations', async (route) => {
@@ -1,4 +1,4 @@
1
- import { expect, test } from '../../fixtures/index.js';
1
+ import { expect, baseTest as test } from '../../fixtures/index.js';
2
2
  test.describe('Training', () => {
3
3
  // Prevent worker from being logged in automatically
4
4
  test.use({ storageState: { cookies: [], origins: [] } });
@@ -1,4 +1,4 @@
1
- import { expect, test } from '../../../index.js';
1
+ import { expect, authenticatedTest as test } from '../../../index.js';
2
2
  let organizationId;
3
3
  let appCollectionName;
4
4
  let appCollectionId;
@@ -1,5 +1,5 @@
1
1
  import { readFile } from 'node:fs/promises';
2
- import { expect, test } from '../../index.js';
2
+ import { expect, authenticatedTest as test } from '../../index.js';
3
3
  let appId;
4
4
  test.describe('Individual app', () => {
5
5
  test.beforeAll(async ({ createApp, createOrganization, randomTestId }) => {
@@ -1,4 +1,4 @@
1
- import { expect, test } from '../../../index.js';
1
+ import { expect, authenticatedTest as test } from '../../../index.js';
2
2
  test.describe('Appsemble OAuth2 app login', () => {
3
3
  test.fixme('should work', async ({ page }) => {
4
4
  await page.getByRole('link', { name: 'Login' }).click();
@@ -1,4 +1,4 @@
1
- import { expect, test } from '../../../index.js';
1
+ import { expect, authenticatedTest as test } from '../../../index.js';
2
2
  test.describe('Demo login', () => {
3
3
  test.fixme('should work', async ({ page }) => {
4
4
  await page.getByRole('link', { name: 'Login' }).click();
@@ -1,4 +1,4 @@
1
- import { expect, test } from '../../../index.js';
1
+ import { expect, authenticatedTest as test } from '../../../index.js';
2
2
  test.describe('App invite', () => {
3
3
  test.fixme('should work', async ({ page }) => {
4
4
  await expect(page.getByRole('heading', { name: 'Example Page A' })).toBeVisible();
@@ -1,4 +1,4 @@
1
- import { expect, test } from '../../../index.js';
1
+ import { expect, authenticatedTest as test } from '../../../index.js';
2
2
  let app;
3
3
  let secret;
4
4
  test.describe('App OAuth2 login', () => {
@@ -1,4 +1,4 @@
1
- import { expect, test } from '../../../index.js';
1
+ import { expect, authenticatedTest as test } from '../../../index.js';
2
2
  test.describe('App password login', () => {
3
3
  test.fixme('should work', async ({ page }) => {
4
4
  await page.getByRole('link', { name: 'Login' }).click();
@@ -1,4 +1,4 @@
1
- import { expect, test } from '../../../index.js';
1
+ import { expect, authenticatedTest as test } from '../../../index.js';
2
2
  test.describe('App registration', () => {
3
3
  test.fixme('should work', async ({ page }) => {
4
4
  await page.getByRole('link', { name: 'Login' }).click();
@@ -1,4 +1,4 @@
1
- import { expect, test } from '../../../index.js';
1
+ import { expect, authenticatedTest as test } from '../../../index.js';
2
2
  test.describe('App SAML login', () => {
3
3
  test.fixme('should work', async ({ page }) => {
4
4
  await page.getByRole('link', { name: 'Login' }).click();
@@ -1,4 +1,4 @@
1
- import { expect, test } from '../../index.js';
1
+ import { expect, authenticatedTest as test } from '../../index.js';
2
2
  let organizationId;
3
3
  test.describe('Organizations', () => {
4
4
  test.beforeAll(async ({ createOrganization, randomTestId }) => {
@@ -1,15 +1,26 @@
1
- import { expect, test } from '../../../fixtures/index.js';
2
- const organization = 'Appsemble';
1
+ import { updateSubscription } from '@appsemble/node-utils';
2
+ import { SubscriptionPlanType } from '@appsemble/types';
3
+ import { expect, authenticatedTest as test } from '../../../fixtures/index.js';
4
+ let organizationId;
3
5
  const email = 'test+test_mode@test.com';
4
6
  const streetName = 'street one';
5
7
  const houseNumber = '12a';
6
8
  const city = 'Eindhoven';
7
9
  const zipCode = '1234DF';
8
10
  const country = 'NL';
11
+ const { CI } = process.env;
9
12
  test.describe('Payments', () => {
10
- const { CI } = process.env;
13
+ test.beforeAll(async ({ createOrganization, randomTestId }) => {
14
+ organizationId = (await createOrganization({ id: randomTestId() })).id;
15
+ });
16
+ test.beforeEach(async () => {
17
+ await updateSubscription(organizationId, SubscriptionPlanType.Standard);
18
+ });
19
+ test.afterAll(async ({ deleteOrganization }) => {
20
+ await deleteOrganization(organizationId);
21
+ });
11
22
  test('should cancel a subscription', async ({ page }) => {
12
- await page.goto(`/en/organizations/${organization.toLowerCase()}/subscriptions`);
23
+ await page.goto(`/en/organizations/${organizationId}/subscriptions`);
13
24
  await page
14
25
  .locator('.card:has-text("STANDARD")')
15
26
  .getByRole('button', { name: 'Cancel' })
@@ -24,15 +35,15 @@ test.describe('Payments', () => {
24
35
  }
25
36
  });
26
37
  (CI ? test.skip : test)('should confirm correct redirect by extension', async ({ page }) => {
27
- await page.goto(`/en/organizations/${organization.toLowerCase()}/subscriptions`);
38
+ await page.goto(`/en/organizations/${organizationId}/subscriptions`);
28
39
  await page.locator('.card:has-text("STANDARD")').getByRole('link', { name: 'Extend' }).click();
29
- await expect(page).toHaveTitle('Activate · Appsemble', { timeout: 10000 });
40
+ await expect(page).toHaveTitle('Activate · Appsemble');
30
41
  });
31
42
  test('should purchase a subscription', async ({ page }) => {
32
- await page.goto(`/en/organizations/${organization.toLowerCase()}/subscriptions`);
43
+ await page.goto(`/en/organizations/${organizationId}/subscriptions`);
33
44
  await page.locator('.card:has-text("EXTENSIVE")').getByRole('link', { name: 'Switch' }).click();
34
45
  await expect(page.getByText('Select type of')).toBeVisible();
35
- await expect(page.getByText('Total subscription priceActive subscription discountCoupon discountTotal price')).toBeVisible();
46
+ await expect(page.getByText('Total subscription price')).toBeVisible();
36
47
  await page.getByRole('button', { name: 'Checkout ' }).click();
37
48
  await page.getByLabel('Email').fill(email);
38
49
  await page.getByLabel('Street name').fill(streetName);
@@ -40,23 +51,23 @@ test.describe('Payments', () => {
40
51
  await page.getByLabel('City').fill(city);
41
52
  await page.getByLabel('Zip code').fill(zipCode);
42
53
  await page.getByLabel('Country').selectOption(country);
43
- await page.getByLabel('Name', { exact: true }).fill(organization);
54
+ await page.getByLabel('Name', { exact: true }).fill(organizationId);
44
55
  await page.getByRole('button').getByText('Continue').click();
45
- await expect(page.getByText('Total subscription priceActive subscription discountCoupon discountVAT 21%Total price')).toBeVisible();
56
+ await expect(page.getByText('Total subscription price')).toBeVisible();
46
57
  // eslint-disable-next-line playwright/no-conditional-in-test
47
58
  if (!CI) {
48
59
  await page.getByRole('button', { name: 'Summary ' }).click();
49
- await expect(page).toHaveTitle('Appsemble b.v.', { timeout: 10000 });
60
+ await expect(page).toHaveTitle('Appsemble b.v.');
50
61
  await page.getByTestId('sepa_debit-accordion-item').click();
51
62
  await page.locator('[placeholder="\\NL00 AAAA 0000 0000 00"]').click();
52
63
  await page.locator('[placeholder="\\NL00 AAAA 0000 0000 00"]').fill('NL39RABO0300065264');
53
- await page.getByLabel('Name on account').fill(organization);
64
+ await page.getByLabel('Name on account').fill(organizationId);
54
65
  await page.getByPlaceholder('Address line 1').fill(streetName);
55
66
  await page.getByPlaceholder('Postal code').fill(zipCode);
56
67
  await page.getByPlaceholder('City').fill(city);
57
68
  await page.getByTestId('hosted-payment-submit-button').click();
58
- await expect(page.getByText('Purchase successful')).toBeVisible({ timeout: 30000 });
59
- await expect(page.getByText('New expiration date')).toBeVisible({ timeout: 60000 });
69
+ await expect(page.getByText('Purchase successful')).toBeVisible();
70
+ await expect(page.getByText('New expiration date')).toBeVisible();
60
71
  await expect(page.getByText('Subscription plan')).toBeVisible();
61
72
  await expect(page.getByText('Renewal period')).toBeVisible();
62
73
  await expect(page.getByText('extensive')).toBeVisible();
@@ -1,4 +1,4 @@
1
- import { expect, test } from '../../index.js';
1
+ import { expect, authenticatedTest as test } from '../../index.js';
2
2
  test('should allow to switch languages', async ({ page }) => {
3
3
  await page.goto('/en/apps');
4
4
  await page.locator('button', { hasText: /EN/ }).click();
@@ -1,11 +1,9 @@
1
- import { expect, test } from '../../index.js';
1
+ import { expect, authenticatedTest as test } from '../../index.js';
2
2
  test.describe('Training', () => {
3
3
  test.beforeEach(async ({ page, resetTrainingProgress }) => {
4
4
  await resetTrainingProgress();
5
5
  await page.goto('/en/trainings');
6
6
  });
7
- // We only have 1 account, so tests can influence each other
8
- test.describe.configure({ mode: 'serial' });
9
7
  test("should show 'Training' in breadcrumbs", async ({ page }) => {
10
8
  await expect(page.getByLabel('Breadcrumbs').getByRole('listitem').filter({ hasText: 'Training' })).toBeVisible();
11
9
  });
@@ -1,10 +0,0 @@
1
- import { expect, test as setup } from '../index.js';
2
- const { BOT_ACCOUNT_EMAIL, BOT_ACCOUNT_PASSWORD } = process.env;
3
- setup('authenticate', async ({ loginUser }) => {
4
- expect(BOT_ACCOUNT_EMAIL && BOT_ACCOUNT_PASSWORD).not.toBeUndefined();
5
- const accessToken = await loginUser(BOT_ACCOUNT_EMAIL, BOT_ACCOUNT_PASSWORD, true);
6
- expect(accessToken).toStrictEqual(expect.any(String));
7
- // Playwright uses this environment variable to authenticate API requests
8
- process.env.ACCESS_TOKEN = accessToken;
9
- });
10
- //# sourceMappingURL=auth.setup.js.map