@appsemble/e2e 0.32.2

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 (76) hide show
  1. package/LICENSE.md +126 -0
  2. package/README.md +64 -0
  3. package/fixtures/expect/index.d.ts +5 -0
  4. package/fixtures/expect/index.js +4 -0
  5. package/fixtures/expect/training/index.d.ts +17 -0
  6. package/fixtures/expect/training/index.js +30 -0
  7. package/fixtures/index.d.ts +2 -0
  8. package/fixtures/index.js +3 -0
  9. package/fixtures/test/app/index.d.ts +24 -0
  10. package/fixtures/test/app/index.js +40 -0
  11. package/fixtures/test/app-collection/index.d.ts +22 -0
  12. package/fixtures/test/app-collection/index.js +42 -0
  13. package/fixtures/test/demo-app/index.d.ts +15 -0
  14. package/fixtures/test/demo-app/index.js +22 -0
  15. package/fixtures/test/group/index.d.ts +11 -0
  16. package/fixtures/test/group/index.js +13 -0
  17. package/fixtures/test/index.d.ts +1 -0
  18. package/fixtures/test/index.js +11 -0
  19. package/fixtures/test/live-app/index.d.ts +27 -0
  20. package/fixtures/test/live-app/index.js +50 -0
  21. package/fixtures/test/resource/index.d.ts +18 -0
  22. package/fixtures/test/resource/index.js +29 -0
  23. package/fixtures/test/studio/index.d.ts +17 -0
  24. package/fixtures/test/studio/index.js +33 -0
  25. package/fixtures/test/training/index.d.ts +7 -0
  26. package/fixtures/test/training/index.js +18 -0
  27. package/index.d.ts +2 -0
  28. package/index.js +3 -0
  29. package/package.json +52 -0
  30. package/playwright.config.d.ts +5 -0
  31. package/playwright.config.js +48 -0
  32. package/setup/auth.setup.d.ts +1 -0
  33. package/setup/auth.setup.js +10 -0
  34. package/tests/studio/app-collections/app-collections.spec.d.ts +1 -0
  35. package/tests/studio/app-collections/app-collections.spec.js +158 -0
  36. package/tests/studio/apps/app.spec.d.ts +1 -0
  37. package/tests/studio/apps/app.spec.js +79 -0
  38. package/tests/studio/apps.spec.d.ts +1 -0
  39. package/tests/studio/apps.spec.js +30 -0
  40. package/tests/studio/blocks.spec.d.ts +1 -0
  41. package/tests/studio/blocks.spec.js +20 -0
  42. package/tests/studio/docs.spec.d.ts +1 -0
  43. package/tests/studio/docs.spec.js +28 -0
  44. package/tests/studio/logins/appsemble.spec.d.ts +1 -0
  45. package/tests/studio/logins/appsemble.spec.js +14 -0
  46. package/tests/studio/logins/demo.spec.d.ts +1 -0
  47. package/tests/studio/logins/demo.spec.js +9 -0
  48. package/tests/studio/logins/invite.spec.d.ts +1 -0
  49. package/tests/studio/logins/invite.spec.js +12 -0
  50. package/tests/studio/logins/oauth2.spec.d.ts +1 -0
  51. package/tests/studio/logins/oauth2.spec.js +56 -0
  52. package/tests/studio/logins/password.spec.d.ts +1 -0
  53. package/tests/studio/logins/password.spec.js +14 -0
  54. package/tests/studio/logins/register.spec.d.ts +1 -0
  55. package/tests/studio/logins/register.spec.js +14 -0
  56. package/tests/studio/logins/saml.spec.d.ts +1 -0
  57. package/tests/studio/logins/saml.spec.js +14 -0
  58. package/tests/studio/organizations.spec.d.ts +1 -0
  59. package/tests/studio/organizations.spec.js +33 -0
  60. package/tests/studio/root.spec.d.ts +1 -0
  61. package/tests/studio/root.spec.js +8 -0
  62. package/tests/studio/trainings/constants.d.ts +4 -0
  63. package/tests/studio/trainings/constants.js +5 -0
  64. package/tests/studio/trainings/logged-in.spec.d.ts +1 -0
  65. package/tests/studio/trainings/logged-in.spec.js +43 -0
  66. package/tests/studio/trainings/logged-out.spec.d.ts +1 -0
  67. package/tests/studio/trainings/logged-out.spec.js +42 -0
  68. package/tests/template-apps/empty.spec.d.ts +1 -0
  69. package/tests/template-apps/empty.spec.js +14 -0
  70. package/tests/template-apps/holidays.spec.d.ts +1 -0
  71. package/tests/template-apps/holidays.spec.js +25 -0
  72. package/tests/template-apps/notes.spec.d.ts +1 -0
  73. package/tests/template-apps/notes.spec.js +25 -0
  74. package/tests/template-apps/person.spec.d.ts +1 -0
  75. package/tests/template-apps/person.spec.js +25 -0
  76. package/vitest.config.js +3 -0
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ import { expect, test } from '../../../index.js';
2
+ test.describe('App password login', () => {
3
+ test.fixme('should work', async ({ page }) => {
4
+ await page.getByRole('link', { name: 'Login' }).click();
5
+ await page.getByRole('button', { name: 'Login with Appsemble' }).click();
6
+ await expect(page.getByRole('heading', { name: 'Example Page A' })).toBeVisible();
7
+ });
8
+ test.fixme('should handle app member email conflict', async ({ page }) => {
9
+ await page.getByRole('link', { name: 'Login' }).click();
10
+ await page.getByRole('button', { name: 'Login with Appsemble' }).click();
11
+ await expect(page.getByRole('heading', { name: 'Example Page A' })).toBeVisible();
12
+ });
13
+ });
14
+ //# sourceMappingURL=password.spec.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ import { expect, test } from '../../../index.js';
2
+ test.describe('App registration', () => {
3
+ test.fixme('should work', async ({ page }) => {
4
+ await page.getByRole('link', { name: 'Login' }).click();
5
+ await page.getByRole('button', { name: 'Login with Appsemble' }).click();
6
+ await expect(page.getByRole('heading', { name: 'Example Page A' })).toBeVisible();
7
+ });
8
+ test.fixme('should handle app member email conflict', async ({ page }) => {
9
+ await page.getByRole('link', { name: 'Login' }).click();
10
+ await page.getByRole('button', { name: 'Login with Appsemble' }).click();
11
+ await expect(page.getByRole('heading', { name: 'Example Page A' })).toBeVisible();
12
+ });
13
+ });
14
+ //# sourceMappingURL=register.spec.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ import { expect, test } from '../../../index.js';
2
+ test.describe('App SAML login', () => {
3
+ test.fixme('should work', async ({ page }) => {
4
+ await page.getByRole('link', { name: 'Login' }).click();
5
+ await page.getByRole('button', { name: 'Login with SAML' }).click();
6
+ await expect(page.getByRole('heading', { name: 'Example Page A' })).toBeVisible();
7
+ });
8
+ test.fixme('should handle app member email conflict', async ({ page }) => {
9
+ await page.getByRole('link', { name: 'Login' }).click();
10
+ await page.getByRole('button', { name: 'Login with Appsemble' }).click();
11
+ await expect(page.getByRole('heading', { name: 'Example Page A' })).toBeVisible();
12
+ });
13
+ });
14
+ //# sourceMappingURL=saml.spec.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,33 @@
1
+ import { expect, test } from '../../index.js';
2
+ test.describe('Organizations', () => {
3
+ test.beforeEach(async ({ page }) => {
4
+ await page.goto('/en/organizations');
5
+ });
6
+ test('should render a list of organizations', async ({ page }) => {
7
+ await expect(page.getByRole('link', { name: 'Appsemble appsemble', exact: true })).toBeVisible();
8
+ });
9
+ test('should link to organization details', async ({ page }) => {
10
+ await page.getByRole('link', { name: 'Appsemble appsemble', exact: true }).click();
11
+ await expect(page.getByText('The open source low-code app building platform')).toBeVisible();
12
+ await expect(page.getByRole('heading', { name: 'Apps', exact: true })).toBeVisible();
13
+ await expect(page.getByRole('heading', { name: 'Blocks', exact: true })).toBeVisible();
14
+ await expect(page.getByText('Unlittered')).toBeVisible();
15
+ await expect(page.getByText('action-button')).toBeVisible();
16
+ });
17
+ test('should cancel the deletion of invite', async ({ page }) => {
18
+ await page.goto('/en/organizations/appsemble/members');
19
+ await page.click('button.button');
20
+ await page.fill('input[name="email"]', 'e2e@appsemble.com');
21
+ await page.click('button[type="submit"]');
22
+ await page.click('button[title="Delete invite"]');
23
+ await page.click('button[type="button"]:has-text("Cancel")');
24
+ await expect(page.getByRole('paragraph', { name: 'Add new members' })).toBeHidden();
25
+ });
26
+ test('should delete invite', async ({ page }) => {
27
+ await page.goto('/en/organizations/appsemble/members');
28
+ await page.click('button[title="Delete invite"]');
29
+ await page.click('button[type="button"]:has-text("Delete invite")');
30
+ await expect(page.locator('table tr:has-text("e2e@appsemble.com")')).toBeHidden();
31
+ });
32
+ });
33
+ //# sourceMappingURL=organizations.spec.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ import { expect, test } from '../../index.js';
2
+ test('should allow to switch languages', async ({ page }) => {
3
+ await page.goto('/en/apps');
4
+ await page.locator('button', { hasText: /EN/ }).click();
5
+ await page.locator('button:has-text("Dutch (Nederlands)")').click();
6
+ await expect(page.getByRole('heading', { name: 'Alle Apps', exact: true })).toBeVisible();
7
+ });
8
+ //# sourceMappingURL=root.spec.js.map
@@ -0,0 +1,4 @@
1
+ export declare const availableColor = "rgb(255, 255, 255)";
2
+ export declare const inProgressColor = "rgb(255, 127, 39)";
3
+ export declare const completedColor = "rgb(34, 177, 76)";
4
+ export declare const blockedColor = "rgb(211, 211, 211)";
@@ -0,0 +1,5 @@
1
+ export const availableColor = 'rgb(255, 255, 255)';
2
+ export const inProgressColor = 'rgb(255, 127, 39)';
3
+ export const completedColor = 'rgb(34, 177, 76)';
4
+ export const blockedColor = 'rgb(211, 211, 211)';
5
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,43 @@
1
+ import { expect, test } from '../../../fixtures/index.js';
2
+ test.beforeEach(async ({ page, resetTrainingProgress }) => {
3
+ await resetTrainingProgress();
4
+ await page.goto('/en/trainings');
5
+ });
6
+ // We only have 1 account, so tests can influence each other
7
+ test.describe.configure({ mode: 'serial' });
8
+ test('should show the first chapter unlocked and the second one blocked', async ({ page }) => {
9
+ const nodeStatus = [
10
+ { name: 'rf__node-introduction', status: 'available' },
11
+ { name: 'rf__node-what-is-appsemble', status: 'available' },
12
+ { name: 'rf__node-get-familiar-with-the-studio', status: 'available' },
13
+ { name: 'rf__node-how-to-create-an-app', status: 'blocked' },
14
+ { name: 'rf__node-app-structure', status: 'blocked' },
15
+ { name: 'rf__node-what-is-a-page', status: 'blocked' },
16
+ { name: 'rf__node-what-is-a-block', status: 'blocked' },
17
+ { name: 'rf__node-simple-app', status: 'blocked' },
18
+ ];
19
+ for (const { name, status } of nodeStatus) {
20
+ await expect(page.getByTestId(name)).toHaveChapterStatus(status);
21
+ }
22
+ });
23
+ test('should unlock next chapter once blocking chapter is completed', async ({ page }) => {
24
+ await page.getByTestId('rf__node-what-is-appsemble').getByRole('link').click();
25
+ await page.getByRole('button', { name: 'Click to complete' }).click();
26
+ await page.getByRole('button', { name: 'To "Get familiar with the studio"' }).click();
27
+ await page.getByRole('button', { name: 'Click to complete' }).click();
28
+ await page.getByRole('button', { name: 'Back to tree' }).click();
29
+ const nodeStatus = [
30
+ { name: 'rf__node-introduction', status: 'completed' },
31
+ { name: 'rf__node-what-is-appsemble', status: 'completed' },
32
+ { name: 'rf__node-get-familiar-with-the-studio', status: 'completed' },
33
+ { name: 'rf__node-how-to-create-an-app', status: 'available' },
34
+ { name: 'rf__node-app-structure', status: 'available' },
35
+ { name: 'rf__node-what-is-a-page', status: 'available' },
36
+ { name: 'rf__node-what-is-a-block', status: 'available' },
37
+ { name: 'rf__node-simple-app', status: 'available' },
38
+ ];
39
+ for (const { name, status } of nodeStatus) {
40
+ await expect(page.getByTestId(name)).toHaveChapterStatus(status);
41
+ }
42
+ });
43
+ //# sourceMappingURL=logged-in.spec.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,42 @@
1
+ import { availableColor } from './constants.js';
2
+ import { expect, test } from '../../../fixtures/index.js';
3
+ test.beforeEach(async ({ page }) => {
4
+ await page.goto('/en/trainings');
5
+ await expect(page.getByLabel('Breadcrumbs').getByRole('listitem').filter({ hasText: 'Training' })).toBeVisible();
6
+ });
7
+ test.use({ storageState: { cookies: [], origins: [] } });
8
+ test('should render first chapter in training tree', async ({ page }) => {
9
+ await expect(page.getByTestId('rf__node-introduction')).toBeVisible();
10
+ });
11
+ test('should show banner if user is not logged in', async ({ page }) => {
12
+ await expect(page.getByText('Warning: You are currently not logged in. While logged out you can access all trainings, but progress will not be saved')).toBeVisible();
13
+ });
14
+ test('should have all trainings unlocked if user is not logged in', async ({ page }) => {
15
+ // Wait for initialization since locator.all() does not wait for elements to be visible
16
+ await page.getByTestId('rf__node-introduction').waitFor({ state: 'visible' });
17
+ const statusCircles = await page.getByTestId('status-circle').all();
18
+ expect(statusCircles.length).toBeGreaterThan(0);
19
+ for (const statusCircle of statusCircles) {
20
+ await expect(statusCircle).toHaveCSS('background-color', availableColor);
21
+ }
22
+ const blockedNodeTitles = await page.getByTestId('node-title-blocked').all();
23
+ expect(blockedNodeTitles.length).toBe(0);
24
+ });
25
+ test('should navigate to training once the link is clicked', async ({ page }) => {
26
+ await page.getByTestId('rf__node-what-is-appsemble').getByRole('link').click();
27
+ await expect(page.getByRole('heading', { name: 'Appsemble Introduction ' })).toBeVisible();
28
+ });
29
+ test('should update training and chapter status once training is completed', async ({ page }) => {
30
+ await page.getByTestId('rf__node-what-is-appsemble').getByRole('link').click();
31
+ await page.getByRole('button', { name: 'Click to complete' }).click();
32
+ await page.getByRole('button', { name: 'Back to tree' }).click();
33
+ await expect(page.getByTestId('rf__node-introduction')).toHaveChapterStatus('in progress');
34
+ await expect(page.getByTestId('rf__node-what-is-appsemble')).toHaveChapterStatus('completed');
35
+ });
36
+ test('should allow user to click through chapter trainings', async ({ page }) => {
37
+ await page.getByTestId('rf__node-what-is-appsemble').getByRole('link').click();
38
+ await page.getByRole('button', { name: 'Click to complete' }).click();
39
+ await page.getByRole('button', { name: 'To "Get familiar with the studio"' }).click();
40
+ await expect(page.getByRole('heading', { name: 'Get familiar with the studio' })).toBeVisible();
41
+ });
42
+ //# sourceMappingURL=logged-out.spec.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ import { expect, test } from '../../index.js';
2
+ test.describe('Empty', () => {
3
+ test.beforeEach(async ({ page, visitApp }) => {
4
+ await visitApp('empty');
5
+ await page.waitForURL('**/example-page-a');
6
+ });
7
+ test('should navigate to the second page and back', async ({ page }) => {
8
+ await page.click('a.button');
9
+ await expect(page.getByRole('heading', { name: 'Example Page B' })).toBeVisible();
10
+ await page.click('a.button');
11
+ await expect(page.getByRole('heading', { name: 'Example Page A' })).toBeVisible();
12
+ });
13
+ });
14
+ //# sourceMappingURL=empty.spec.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,25 @@
1
+ import { expect, test } from '../../index.js';
2
+ test.describe('Holidays', () => {
3
+ test.beforeEach(async ({ page, visitApp }) => {
4
+ await page.route('/api/apps/*/actions/pages.0.tabs.0.blocks.0.actions.onLoad*', (route) => {
5
+ route.fulfill({ path: 'mock-data/holidays-nl.json' });
6
+ });
7
+ await page.route('/api/apps/*/actions/pages.0.tabs.1.blocks.0.actions.onLoad*', (route) => {
8
+ route.fulfill({ path: 'mock-data/holidays-de.json' });
9
+ });
10
+ await page.route('/api/apps/*/actions/pages.1.tabs.0.blocks.0.actions.onLoad*', (route) => {
11
+ route.fulfill({ path: 'mock-data/holidays-us.json' });
12
+ });
13
+ await visitApp('holidays');
14
+ await page.waitForURL('**/holidays-in-europe/netherlands');
15
+ });
16
+ test('should navigate to the second tab', async ({ page }) => {
17
+ await page.click('text=Germany');
18
+ await expect(page.getByText('Mariä Himmelfahrt')).toBeVisible();
19
+ });
20
+ test('should navigate to the American holidays page', async ({ page }) => {
21
+ await page.click('text=Holidays in America');
22
+ await expect(page.getByText('Independence Day')).toBeVisible();
23
+ });
24
+ });
25
+ //# sourceMappingURL=holidays.spec.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,25 @@
1
+ import { expect, test } from '../../index.js';
2
+ test.describe('Notes', () => {
3
+ test.beforeAll(async ({ getAppId, giveAppConsent }) => {
4
+ const appId = await getAppId('notes');
5
+ await giveAppConsent(appId);
6
+ });
7
+ test.beforeEach(async ({ loginAppAppsembleOAuth, page, visitApp }) => {
8
+ await visitApp('notes');
9
+ await loginAppAppsembleOAuth();
10
+ await page.waitForURL('**/notes');
11
+ });
12
+ test('should create a new note and view it', async ({ page }) => {
13
+ const date = Date.now();
14
+ await page.click('.button.is-rounded');
15
+ await page.fill('#title', `Title ${date}`);
16
+ await page.fill('#body', `Body ${date}`);
17
+ await page.click('button[type="submit"]');
18
+ const entry = page.locator(`text=Title ${date}`);
19
+ await expect(entry).toBeVisible();
20
+ await entry.click();
21
+ await expect(page.getByPlaceholder('title')).toHaveValue(`Title ${date}`);
22
+ await expect(page.getByPlaceholder('body')).toHaveValue(`Body ${date}`);
23
+ });
24
+ });
25
+ //# sourceMappingURL=notes.spec.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,25 @@
1
+ import { expect, test } from '../../index.js';
2
+ test.describe('Person', () => {
3
+ test.beforeEach(async ({ page, visitApp }) => {
4
+ await visitApp('person');
5
+ await page.waitForURL('**/person-registration-form');
6
+ });
7
+ test('should submit a new person and view it', async ({ page }) => {
8
+ const date = Date.now();
9
+ const firstName = `First name ${date}`;
10
+ const lastName = `Last name ${date}`;
11
+ const email = `Email${date}@example.com`;
12
+ const description = `Description ${date}`;
13
+ await page.fill('[placeholder="First name"]', firstName);
14
+ await page.fill('[placeholder="Last name"]', lastName);
15
+ await page.fill('[placeholder="Email"]', email);
16
+ await page.fill('[placeholder="Description"]', description);
17
+ await page.click('button[type="submit"]');
18
+ await page.click(`td:has-text("${firstName}")`);
19
+ await expect(page.getByText(firstName)).toBeVisible();
20
+ await expect(page.getByText(lastName)).toBeVisible();
21
+ await expect(page.getByText(email)).toBeVisible();
22
+ await expect(page.getByText(description)).toBeVisible();
23
+ });
24
+ });
25
+ //# sourceMappingURL=person.spec.js.map
@@ -0,0 +1,3 @@
1
+ import { createVitestConfig } from '../../config/vitest/config.js';
2
+
3
+ export default createVitestConfig(import.meta);