Skip to content

Commit 530c337

Browse files
committed
Added resource and profile e2e tests
1 parent 6bd33fb commit 530c337

File tree

5 files changed

+211
-13
lines changed

5 files changed

+211
-13
lines changed

tests/data/resource.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"id": 1,
3+
"type": "local",
4+
"name": "test resource",
5+
"host": null,
6+
"jobs_local_dir": "/path/to/fractal-server/data-jobs",
7+
"jobs_runner_config": {
8+
"parallel_tasks_per_job": null
9+
},
10+
"jobs_slurm_python_worker": null,
11+
"jobs_poll_interval": 0,
12+
"tasks_local_dir": "/path/to/fractal-server/data-tasks",
13+
"tasks_python_config": {
14+
"versions": {
15+
"3.12": "/path/to/fractal-server/venv/bin/python"
16+
},
17+
"pip_cache_dir": null,
18+
"default_version": "3.12"
19+
},
20+
"tasks_pixi_config": {}
21+
}

tests/utils.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,17 @@ export async function closeModal(page) {
2626
await expect(modal).not.toBeVisible();
2727
}
2828

29+
/**
30+
* Wait until modal is opened
31+
* @param {import('@playwright/test').Page} page
32+
* @returns {Promise<import('@playwright/test').Locator>}
33+
*/
34+
export async function waitModal(page) {
35+
const modal = page.locator('.modal.show');
36+
await modal.waitFor();
37+
return modal;
38+
}
39+
2940
/**
3041
* Wait until modal is closed
3142
* @param {import('@playwright/test').Page} page
@@ -143,3 +154,15 @@ export async function logout(page, email) {
143154
await waitPageLoading(page);
144155
await expect(page.getByRole('link', { name: 'Login' }).first()).toBeVisible();
145156
}
157+
158+
/**
159+
* @param {import('@playwright/test').Page} page
160+
* @param {string} selectorText
161+
* @param {string} filePath
162+
*/
163+
export async function setUploadFile(page, selectorText, filePath) {
164+
const fileChooserPromise = page.waitForEvent('filechooser');
165+
await page.getByText(selectorText).click();
166+
const fileChooser = await fileChooserPromise;
167+
await fileChooser.setFiles(filePath);
168+
}

tests/v2/add_single_task.spec.js

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expect, test } from '@playwright/test';
2-
import { waitModalClosed, waitPageLoading, waitStopSpinnerIn } from '../utils.js';
2+
import { setUploadFile, waitModalClosed, waitPageLoading, waitStopSpinnerIn } from '../utils.js';
33
import { fileURLToPath } from 'url';
44
import path from 'path';
55
import { collapseExpandedRows, deleteTask } from './task_utils.js';
@@ -392,15 +392,3 @@ async function getExpandedTaskRow(page) {
392392
}
393393
throw new Error('Unable to find expanded task row');
394394
}
395-
396-
/**
397-
* @param {import('@playwright/test').Page} page
398-
* @param {string} selectorText
399-
* @param {string} filePath
400-
*/
401-
async function setUploadFile(page, selectorText, filePath) {
402-
const fileChooserPromise = page.waitForEvent('filechooser');
403-
await page.getByText(selectorText).click();
404-
const fileChooser = await fileChooserPromise;
405-
await fileChooser.setFiles(filePath);
406-
}

tests/v2/profile_crud.spec.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { expect, test } from '@playwright/test';
2+
import { setUploadFile, waitModal, waitModalClosed, waitPageLoading } from '../utils.js';
3+
import path from 'path';
4+
import { fileURLToPath } from 'url';
5+
6+
const __filename = fileURLToPath(import.meta.url);
7+
const __dirname = path.dirname(__filename);
8+
9+
const resourceFile = path.join(__dirname, '..', 'data', 'resource.json');
10+
11+
const randomResourceName = `${Math.random().toString(36).substring(7)} resource`;
12+
const randomProfileName = `${Math.random().toString(36).substring(7)} profile`;
13+
14+
test('Create, update and delete a profile', async ({ page }) => {
15+
await test.step('Create a new resource', async () => {
16+
await page.goto('/v2/admin/resources/create');
17+
await waitPageLoading(page);
18+
await setUploadFile(page, 'Load from file', resourceFile);
19+
await expect(page.locator('textarea')).toHaveValue(/{/);
20+
const text = await page.locator('textarea').inputValue();
21+
const resource = JSON.parse(/**@type {string} */ (text));
22+
await page.locator('textarea').fill(JSON.stringify({ ...resource, name: randomResourceName }));
23+
await page.getByRole('button', { name: 'Create resource' }).click();
24+
await page.waitForURL(/\/v2\/admin\/resources$/);
25+
await waitPageLoading(page);
26+
});
27+
28+
await test.step('Open resource profiles', async () => {
29+
await page
30+
.getByRole('row', { name: randomResourceName })
31+
.getByRole('link', { name: 'Profiles' })
32+
.click();
33+
await page.waitForURL(/\/v2\/admin\/resources\/\d+\/profiles$/);
34+
await waitPageLoading(page);
35+
});
36+
37+
await test.step('Create new profile', async () => {
38+
await page.getByRole('link', { name: 'New profile' }).click();
39+
await page.waitForURL(/\/v2\/admin\/resources\/\d+\/profiles\/create$/);
40+
await waitPageLoading(page);
41+
await page.getByRole('textbox', { name: 'Profile name' }).fill(randomProfileName);
42+
await page.getByRole('button', { name: 'Save' }).click();
43+
await page.waitForURL(/\/v2\/admin\/resources\/\d+\/profiles$/);
44+
await waitPageLoading(page);
45+
});
46+
47+
await test.step('Open profile page', async () => {
48+
await page
49+
.getByRole('row', { name: randomProfileName })
50+
.getByRole('link', { name: 'Info' })
51+
.click();
52+
await page.waitForURL(/\/v2\/admin\/resources\/\d+\/profiles\/\d+$/);
53+
await waitPageLoading(page);
54+
await expect(page.getByRole('row', { name: randomProfileName })).toBeVisible();
55+
});
56+
57+
await test.step('Edit profile', async () => {
58+
await page.getByRole('link', { name: 'Edit' }).click();
59+
await page.getByRole('textbox', { name: 'Profile name' }).fill(`${randomProfileName}-renamed`);
60+
await page.getByRole('button', { name: 'Save' }).click();
61+
await expect(page.getByText('Profile successfully updated')).toBeVisible();
62+
});
63+
64+
await test.step('Delete profile', async () => {
65+
await page.getByRole('link', { name: 'Profiles' }).click();
66+
await page.waitForURL(/\/v2\/admin\/resources\/\d+\/profiles$/);
67+
await waitPageLoading(page);
68+
await page
69+
.getByRole('row', { name: `${randomProfileName}-renamed` })
70+
.getByRole('button', { name: 'Delete' })
71+
.click();
72+
const modal = await waitModal(page);
73+
await modal.getByRole('button', { name: 'Confirm' }).click();
74+
await waitModalClosed(page);
75+
await expect(page.getByRole('row', { name: `${randomProfileName}-renamed` })).not.toBeVisible();
76+
});
77+
78+
await test.step('Delete test resource', async () => {
79+
await page.getByRole('link', { name: 'Resources' }).click();
80+
await page.waitForURL(/\/v2\/admin\/resources$/);
81+
await waitPageLoading(page);
82+
await page
83+
.getByRole('row', { name: randomResourceName })
84+
.getByRole('button', { name: 'Delete' })
85+
.click();
86+
const modal = await waitModal(page);
87+
await modal.getByRole('button', { name: 'Confirm' }).click();
88+
await waitModalClosed(page);
89+
await expect(page.getByRole('row', { name: randomResourceName })).not.toBeVisible();
90+
});
91+
});

tests/v2/resource_crud.spec.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { expect, test } from '@playwright/test';
2+
import { setUploadFile, waitModal, waitModalClosed, waitPageLoading } from '../utils.js';
3+
import path from 'path';
4+
import { fileURLToPath } from 'url';
5+
6+
const __filename = fileURLToPath(import.meta.url);
7+
const __dirname = path.dirname(__filename);
8+
9+
const resourceFile = path.join(__dirname, '..', 'data', 'resource.json');
10+
11+
const randomResourceName = `${Math.random().toString(36).substring(7)} resource`;
12+
13+
test('Create, update and delete a resource', async ({ page }) => {
14+
await test.step('Open the admin area', async () => {
15+
await page.goto('/v2/admin');
16+
await waitPageLoading(page);
17+
});
18+
19+
await test.step('Open the new resource page', async () => {
20+
await page.getByRole('link', { name: 'Resources' }).click();
21+
await waitPageLoading(page);
22+
await page.getByRole('link', { name: 'New resource' }).click();
23+
await waitPageLoading(page);
24+
});
25+
26+
await test.step('Create a new resource', async () => {
27+
await setUploadFile(page, 'Load from file', resourceFile);
28+
await expect(page.locator('textarea')).toHaveValue(/{/);
29+
const text = await page.locator('textarea').inputValue();
30+
const resource = JSON.parse(/**@type {string} */ (text));
31+
await page.locator('textarea').fill(JSON.stringify({ ...resource, name: randomResourceName }));
32+
await page.getByRole('button', { name: 'Create resource' }).click();
33+
await page.waitForURL(/\/v2\/admin\/resources$/);
34+
await waitPageLoading(page);
35+
});
36+
37+
await test.step('Open the resource', async () => {
38+
await page
39+
.getByRole('row', { name: randomResourceName })
40+
.getByRole('link', { name: 'Info' })
41+
.click();
42+
await page.waitForURL(/\/v2\/admin\/resources\/\d+$/);
43+
await waitPageLoading(page);
44+
await expect(page.getByText('timestamp_created')).toBeVisible();
45+
});
46+
47+
await test.step('Update the resource', async () => {
48+
await page.getByRole('link', { name: 'Edit' }).click();
49+
await page.waitForURL(/\/v2\/admin\/resources\/\d+\/edit$/);
50+
await waitPageLoading(page);
51+
await expect(page.locator('textarea')).toHaveValue(/{/);
52+
const text = await page.locator('textarea').inputValue();
53+
const resource = JSON.parse(/**@type {string} */ (text));
54+
await page
55+
.locator('textarea')
56+
.fill(JSON.stringify({ ...resource, name: `${randomResourceName}-renamed` }));
57+
await page.getByRole('button', { name: 'Save' }).click();
58+
await expect(page.getByText('Resource updated')).toBeVisible();
59+
});
60+
61+
await test.step('Delete the resource', async () => {
62+
await page.getByRole('link', { name: 'Resources' }).click();
63+
await waitPageLoading(page);
64+
await page
65+
.getByRole('row', { name: `${randomResourceName}-renamed` })
66+
.getByRole('button', { name: 'Delete' })
67+
.click();
68+
const modal = await waitModal(page);
69+
await modal.getByRole('button', { name: 'Confirm' }).click();
70+
await waitModalClosed(page);
71+
await expect(
72+
page.getByRole('row', { name: `${randomResourceName}-renamed` })
73+
).not.toBeVisible();
74+
});
75+
});

0 commit comments

Comments
 (0)