@appsemble/e2e 0.34.2 → 0.34.4
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.
- package/README.md +38 -11
- package/fixtures/test/app/index.d.ts +14 -3
- package/fixtures/test/app/index.js +30 -3
- package/fixtures/test/demo-app/index.d.ts +5 -3
- package/fixtures/test/demo-app/index.js +5 -7
- package/fixtures/test/index.d.ts +1 -1
- package/fixtures/test/index.js +2 -1
- package/fixtures/test/live-app/index.d.ts +10 -0
- package/fixtures/test/live-app/index.js +12 -0
- package/fixtures/test/resource/index.d.ts +4 -2
- package/fixtures/test/resource/index.js +9 -2
- package/fixtures/test/test-utils/index.d.ts +10 -0
- package/fixtures/test/test-utils/index.js +7 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,17 +1,45 @@
|
|
|
1
|
-
#  Appsemble End 2 End Tests
|
|
2
2
|
|
|
3
|
-
> Run end 2 end tests on an Appsemble environment
|
|
3
|
+
> Run end 2 end tests on an Appsemble environment and provide Appsemble fixtures
|
|
4
4
|
|
|
5
|
-
[](https://gitlab.com/appsemble/appsemble/-/releases/0.34.4)
|
|
6
6
|
[](https://prettier.io)
|
|
7
7
|
|
|
8
8
|
## Table of Contents
|
|
9
9
|
|
|
10
|
+
- [How to install](#how-to-install)
|
|
10
11
|
- [Usage](#usage)
|
|
12
|
+
- [Appsemble end-to-end tests](#appsemble-end-to-end-tests)
|
|
13
|
+
- [Authentication](#authentication)
|
|
14
|
+
- [Contribution](#contributing)
|
|
11
15
|
- [License](#license)
|
|
12
16
|
|
|
17
|
+
## How to install
|
|
18
|
+
|
|
19
|
+
You can install the package by running the following at the root of your project:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
npm install @appsemble/e2e
|
|
23
|
+
```
|
|
24
|
+
|
|
13
25
|
## Usage
|
|
14
26
|
|
|
27
|
+
To use the fixtures in your tests, you can import `expect` or `test` at the top of the file.
|
|
28
|
+
|
|
29
|
+
These fixtures can be added to any test by specifying them in the test declaration. Matchers don't
|
|
30
|
+
need to be manually added.
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { expect, test } from '@appsemble/e2e';
|
|
34
|
+
|
|
35
|
+
test('should navigate to app', async ({ visitApp }) => {
|
|
36
|
+
await visitApp('Example app');
|
|
37
|
+
await expect(page.getByText('Example app')).toBeVisible();
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Appsemble end-to-end tests
|
|
42
|
+
|
|
15
43
|
To run end to end tests, run:
|
|
16
44
|
|
|
17
45
|
```sh
|
|
@@ -23,6 +51,11 @@ The tests use [Playwright](https://playwright.dev/).
|
|
|
23
51
|
After each test a video will be saved in the `packages/e2e/test-results/{name-test}` directory for
|
|
24
52
|
further inspection.
|
|
25
53
|
|
|
54
|
+
On the first retry of a failed job, its trace will be uploaded to the same directory. This trace can
|
|
55
|
+
be viewed locally, or it can be uploaded to the
|
|
56
|
+
[online trace viewer](https://trace.playwright.dev/). This shows you step-by-step whawt happened
|
|
57
|
+
during the test as if you ran it using `ui mode`.
|
|
58
|
+
|
|
26
59
|
The end to end tests use the following environment variables:
|
|
27
60
|
|
|
28
61
|
- `BOT_ACCOUNT_EMAIL` — The email address used to login.
|
|
@@ -32,13 +65,7 @@ The end to end tests use the following environment variables:
|
|
|
32
65
|
request review environment instead.
|
|
33
66
|
- `ACCESS_TOKEN` — The access token of the account that's logged in.
|
|
34
67
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
Common end-to-end fixtures are defined under the `fixtures` directory. These are exported for other
|
|
38
|
-
packages to use, like client apps. This can be done by installing this package and importing `test`
|
|
39
|
-
or `expect`.
|
|
40
|
-
|
|
41
|
-
### Authentication
|
|
68
|
+
## Authentication
|
|
42
69
|
|
|
43
70
|
Some fixtures call the Appsemble API using the Playwright `request` object. This expects you to have
|
|
44
71
|
set an access token as environment variable with the name **ACCESS_TOKEN** beforehand. The easiest
|
|
@@ -60,5 +87,5 @@ When writing end-to-end tests, have a look at the
|
|
|
60
87
|
|
|
61
88
|
## License
|
|
62
89
|
|
|
63
|
-
[LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.34.
|
|
90
|
+
[LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.34.4/LICENSE.md) ©
|
|
64
91
|
[Appsemble](https://appsemble.com)
|
|
@@ -1,9 +1,20 @@
|
|
|
1
|
-
import { type App } from '@appsemble/types';
|
|
1
|
+
import { type App, type CreateAppOptions, type PatchAppOptions } from '@appsemble/types';
|
|
2
2
|
export interface AppFixtures {
|
|
3
3
|
/**
|
|
4
|
-
* Create
|
|
4
|
+
* Create a new app for the given organization with the provided options
|
|
5
|
+
*
|
|
6
|
+
* @param organizationId ID of the organization to create the app for
|
|
7
|
+
* @param options Options to create the app with
|
|
8
|
+
* @returns The created app
|
|
9
|
+
*/
|
|
10
|
+
createApp: (organizationId: string, yaml: string, options?: CreateAppOptions) => Promise<App>;
|
|
11
|
+
/**
|
|
12
|
+
* Patches the given app with the provided options
|
|
13
|
+
*
|
|
14
|
+
* @param appId ID of the app to patch
|
|
15
|
+
* @param options What to patch in the app
|
|
5
16
|
*/
|
|
6
|
-
|
|
17
|
+
patchApp: (appId: number, options: PatchAppOptions) => Promise<App>;
|
|
7
18
|
/**
|
|
8
19
|
* Set the role of the user.
|
|
9
20
|
*
|
|
@@ -3,12 +3,19 @@ import stripIndent from 'strip-indent';
|
|
|
3
3
|
import { expect } from '../../expect/index.js';
|
|
4
4
|
export const test = base.extend({
|
|
5
5
|
async createApp({ request }, use) {
|
|
6
|
-
await use(async (
|
|
6
|
+
await use(async (organizationId, yaml, options) => {
|
|
7
7
|
const formData = new FormData();
|
|
8
|
-
formData.append('OrganizationId',
|
|
8
|
+
formData.append('OrganizationId', organizationId);
|
|
9
9
|
formData.append('yaml', stripIndent(yaml));
|
|
10
|
+
if (options) {
|
|
11
|
+
for (const [option, value] of Object.entries(options)) {
|
|
12
|
+
if (value !== undefined) {
|
|
13
|
+
formData.append(option, String(value));
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
10
17
|
const response = await request.post('/api/apps', {
|
|
11
|
-
|
|
18
|
+
multipart: formData,
|
|
12
19
|
headers: {
|
|
13
20
|
Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
|
|
14
21
|
},
|
|
@@ -19,6 +26,26 @@ export const test = base.extend({
|
|
|
19
26
|
return app;
|
|
20
27
|
});
|
|
21
28
|
},
|
|
29
|
+
async patchApp({ request }, use) {
|
|
30
|
+
await use(async (appId, options) => {
|
|
31
|
+
const formData = new FormData();
|
|
32
|
+
for (const [option, value] of Object.entries(options)) {
|
|
33
|
+
if (value !== undefined) {
|
|
34
|
+
formData.append(option, String(value));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const response = await request.patch(`/api/apps/${appId}`, {
|
|
38
|
+
multipart: formData,
|
|
39
|
+
headers: {
|
|
40
|
+
Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
expect(response.status()).toBe(200);
|
|
44
|
+
const app = (await response.json());
|
|
45
|
+
expect(app).not.toBeNull();
|
|
46
|
+
return app;
|
|
47
|
+
});
|
|
48
|
+
},
|
|
22
49
|
async changeAppMemberRole({ browser }, use) {
|
|
23
50
|
await use(async (appId, role) => {
|
|
24
51
|
const page = await browser.newPage();
|
|
@@ -6,10 +6,12 @@ export interface DemoAppFixtures {
|
|
|
6
6
|
*/
|
|
7
7
|
reseedDemoApp: (appId: number) => Promise<void>;
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
9
|
+
* Creates a new demo account with the given role and logs into the app with that account.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
11
|
+
* > **Warning**: Expects you to be in the login screen of a demo app
|
|
12
|
+
*
|
|
13
|
+
* @param role The role to of the account to create
|
|
12
14
|
*/
|
|
13
|
-
|
|
15
|
+
createAndLoginDemoAppMember: (role: string) => Promise<void>;
|
|
14
16
|
}
|
|
15
17
|
export declare const test: import("@playwright/test").TestType<import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions & DemoAppFixtures, import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { test as base } from '@playwright/test';
|
|
1
|
+
import { test as base, expect } from '@playwright/test';
|
|
2
2
|
export const test = base.extend({
|
|
3
3
|
async reseedDemoApp({ browser }, use) {
|
|
4
4
|
await use(async (appId) => {
|
|
@@ -9,13 +9,11 @@ export const test = base.extend({
|
|
|
9
9
|
await page.close();
|
|
10
10
|
});
|
|
11
11
|
},
|
|
12
|
-
async
|
|
12
|
+
async createAndLoginDemoAppMember({ page }, use) {
|
|
13
13
|
await use(async (role) => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
await btn.click();
|
|
18
|
-
}
|
|
14
|
+
await page.getByTestId('app-role').selectOption(role);
|
|
15
|
+
await page.getByTestId('create-account').click();
|
|
16
|
+
await expect(page.getByText('Login failed')).toBeHidden();
|
|
19
17
|
});
|
|
20
18
|
},
|
|
21
19
|
});
|
package/fixtures/test/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
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("./resource/index.js").ResourceFixtures & import("./studio/index.js").StudioFixtures & import("./training/index.js").TrainingFixtures, import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions>;
|
|
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("./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>;
|
package/fixtures/test/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { test as groupFixtures } from './group/index.js';
|
|
|
6
6
|
import { test as liveAppFixtures } from './live-app/index.js';
|
|
7
7
|
import { test as resourceFixtures } from './resource/index.js';
|
|
8
8
|
import { test as studioFixtures } from './studio/index.js';
|
|
9
|
+
import { test as testUtilsFixtures } from './test-utils/index.js';
|
|
9
10
|
import { test as trainingFixtures } from './training/index.js';
|
|
10
|
-
export const test = mergeTests(appFixtures, appCollectionFixtures, demoAppFixtures, groupFixtures, liveAppFixtures, resourceFixtures, studioFixtures, trainingFixtures);
|
|
11
|
+
export const test = mergeTests(appFixtures, appCollectionFixtures, demoAppFixtures, groupFixtures, liveAppFixtures, resourceFixtures, studioFixtures, testUtilsFixtures, trainingFixtures);
|
|
11
12
|
//# sourceMappingURL=index.js.map
|
|
@@ -9,6 +9,16 @@ export interface LiveAppFixtures {
|
|
|
9
9
|
* Login to an app with the Appsemble OAuth2 flow.
|
|
10
10
|
*/
|
|
11
11
|
loginAppAppsembleOAuth: () => Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Logs into an app using the 'Appsemble Login' flow with the provided App Member credentials
|
|
14
|
+
*
|
|
15
|
+
* > **Warning:** Expects the test to be at the login screen of an app that has the "Display
|
|
16
|
+
* Appsemble login method" option enabled.
|
|
17
|
+
*
|
|
18
|
+
* @param email Email of the App Member to log in as
|
|
19
|
+
* @param password Password of the App Member to log in as
|
|
20
|
+
*/
|
|
21
|
+
loginAppAppsembleLogin: (email: string, password: string) => Promise<void>;
|
|
12
22
|
/**
|
|
13
23
|
* Gives the app consent to perform actions on the app member's behalf
|
|
14
24
|
*
|
|
@@ -16,9 +16,21 @@ export const test = base.extend({
|
|
|
16
16
|
const params = new URLSearchParams(page.url().split('Login?')[1]);
|
|
17
17
|
const redirect = params.get('redirect');
|
|
18
18
|
await page.getByTestId('login-with-appsemble').click();
|
|
19
|
+
if (!redirect) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
19
22
|
await page.waitForURL(`**${redirect}`);
|
|
20
23
|
});
|
|
21
24
|
},
|
|
25
|
+
async loginAppAppsembleLogin({ page }, use) {
|
|
26
|
+
await use(async (email, password) => {
|
|
27
|
+
await page.waitForURL('**/Login**');
|
|
28
|
+
await page.getByTestId('email').fill(email);
|
|
29
|
+
await page.getByTestId('password').fill(password);
|
|
30
|
+
await page.getByTestId('login').click();
|
|
31
|
+
await expect(page.getByText('Login failed')).toBeHidden();
|
|
32
|
+
});
|
|
33
|
+
},
|
|
22
34
|
async giveAppConsent({ getLiveAppURL, request }, use) {
|
|
23
35
|
await use(async (appId) => {
|
|
24
36
|
const url = await getLiveAppURL(appId);
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { type Resource } from '@appsemble/types';
|
|
2
2
|
export interface ResourceFixtures {
|
|
3
3
|
/**
|
|
4
|
-
* Create resource
|
|
4
|
+
* Create resource from JSON input.
|
|
5
5
|
*
|
|
6
6
|
* @param appId The ID of the app.
|
|
7
7
|
* @param type The resource type.
|
|
8
8
|
* @param input The resource JSON input.
|
|
9
|
+
* @param assets Any assets that need to be linked to a field
|
|
10
|
+
* @returns The created resource
|
|
9
11
|
*/
|
|
10
|
-
createResource: (appId: number, type: string, input: unknown) => Promise<Resource>;
|
|
12
|
+
createResource: (appId: number, type: string, input: unknown, assets?: Blob[]) => Promise<Resource>;
|
|
11
13
|
/**
|
|
12
14
|
* Delete all resources from an app.
|
|
13
15
|
*
|
|
@@ -2,9 +2,16 @@ import { test as base } from '@playwright/test';
|
|
|
2
2
|
import { expect } from '../../expect/index.js';
|
|
3
3
|
export const test = base.extend({
|
|
4
4
|
async createResource({ request }, use) {
|
|
5
|
-
await use(async (appId, type, input) => {
|
|
5
|
+
await use(async (appId, type, input, assets) => {
|
|
6
|
+
const formData = new FormData();
|
|
7
|
+
formData.append('resource', JSON.stringify(input));
|
|
8
|
+
if (assets) {
|
|
9
|
+
for (const asset of assets) {
|
|
10
|
+
formData.append('assets', asset);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
6
13
|
const response = await request.post(`/api/apps/${appId}/resources/${type}`, {
|
|
7
|
-
|
|
14
|
+
multipart: formData,
|
|
8
15
|
headers: {
|
|
9
16
|
Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
|
|
10
17
|
},
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface TestUtilsFixtures {
|
|
2
|
+
/**
|
|
3
|
+
* Generates a random test ID based on details of the current test
|
|
4
|
+
*
|
|
5
|
+
* @returns Randomized test ID
|
|
6
|
+
* @example '[chrome][index=1][retry=3]-123456'
|
|
7
|
+
*/
|
|
8
|
+
randomTestId: () => string;
|
|
9
|
+
}
|
|
10
|
+
export declare const test: import("@playwright/test").TestType<import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions & TestUtilsFixtures, import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { test as base } from '@playwright/test';
|
|
2
|
+
export const test = base.extend({
|
|
3
|
+
randomTestId({ browserName }, use, testInfo) {
|
|
4
|
+
use(() => `[${browserName}][index=${testInfo.workerIndex}][retry=${testInfo.retry}]-${Math.floor(100000 + Math.random() * 900000)}`);
|
|
5
|
+
},
|
|
6
|
+
});
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appsemble/e2e",
|
|
3
|
-
"version": "0.34.
|
|
3
|
+
"version": "0.34.4",
|
|
4
4
|
"description": "End-to-end tests used for testing Appsemble apps in an existing environment.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"app",
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
"test": "vitest"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@appsemble/utils": "0.34.
|
|
42
|
-
"@appsemble/types": "0.34.
|
|
43
|
-
"@appsemble/lang-sdk": "0.34.
|
|
41
|
+
"@appsemble/utils": "0.34.4",
|
|
42
|
+
"@appsemble/types": "0.34.4",
|
|
43
|
+
"@appsemble/lang-sdk": "0.34.4",
|
|
44
44
|
"jwt-decode": "^4.0.0",
|
|
45
45
|
"@fortawesome/fontawesome-free": "^6.0.0",
|
|
46
46
|
"@playwright/test": "1.51.1",
|