Skip to content

Commit 17a5c3e

Browse files
authored
Merge pull request #420 from fractal-analytics-platform/trim-response-body
Added params to trim response body, loaded running jobs log, improved jobs table layout
2 parents 04dee4c + 055e34a commit 17a5c3e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+731
-225
lines changed

.github/workflows/unit_tests.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,4 @@ jobs:
3333
run: npx vitest run
3434
env:
3535
TZ: Europe/Rome
36+
LANG: it-IT

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
*Note: Numbers like (\#123) point to closed Pull Requests on the fractal-web repository.*
22

3+
# Unreleased
4+
5+
* Improved id and timestamp layout on jobs table (\#420).
6+
* Added query parameters to avoid loading unused fields on the following GET endpoints (\#420):
7+
* `/api/v1/job/`, `/api/v1/{project.id}/job/`, `/admin/job/` (`log` param)
8+
* `/api/v1/task/` (`args_schema` param)
9+
* `/api/v1/dataset/`, `/api/v1/project/{project.id}/dataset/` (`history` param)
10+
* Added `show_tmp_logs=true` query parameter to display log of running jobs (\#420).
11+
312
# 0.9.2
413

514
* Supported JSON Schema `allOf` feature in task arguments form (\#417).

__tests__/JobLogsModal.test.js

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import { describe, it, expect, vi } from 'vitest';
22
import { fireEvent, render } from '@testing-library/svelte';
33

4+
// Mocking public variables
5+
vi.mock('$env/dynamic/public', () => {
6+
return { env: {} };
7+
});
8+
9+
// Mocking bootstrap.Modal
410
class MockModal {
511
show = vi.fn();
612
}
@@ -10,6 +16,9 @@ global.window.bootstrap = {
1016
Modal: MockModal
1117
};
1218

19+
// Mocking fetch
20+
global.fetch = vi.fn();
21+
1322
import JobLogsModal from '../src/lib/components/jobs/JobLogsModal.svelte';
1423

1524
describe('JobLogsModal', async () => {
@@ -18,7 +27,8 @@ describe('JobLogsModal', async () => {
1827
const error = `TASK ERROR:Task id: 20 (Create OME-Zarr structure), e.workflow_task_order=0
1928
TRACEBACK:
2029
Command "/tmp/FRACTAL_TASKS_DIR/.fractal/fractal-tasks-core0.14.1/venv/bin/python" is not valid. Hint: make sure that it is executable.`;
21-
await result.component.show({ status: 'failed', log: error });
30+
mockSuccesfulJobFetch({ id: 1, status: 'failed', log: error });
31+
await result.component.show({ id: 1, status: 'failed', log: null }, false);
2232
const pre = result.container.querySelector('pre');
2333
expect(pre.classList.contains('highlight')).eq(true);
2434
expect(pre.innerHTML).eq(error);
@@ -39,7 +49,8 @@ Traceback (most recent call last):
3949
pydantic.error_wrappers.ValidationError: 1 validation error for CreateOmeZarr
4050
allowed_channels
4151
field required (type=value_error.missing)`;
42-
await result.component.show({ status: 'failed', log: error });
52+
mockSuccesfulJobFetch({ id: 1, status: 'failed', log: error });
53+
await result.component.show({ id: 1, status: 'failed', log: null }, true);
4354
const pre = result.container.querySelector('pre');
4455
let divs = pre.querySelectorAll('div');
4556
expect(divs.length).eq(2);
@@ -66,9 +77,37 @@ allowed_channels
6677
it('display successful log', async () => {
6778
const result = render(JobLogsModal);
6879
const log = 'Successful log...';
69-
await result.component.show({ status: 'done', log });
80+
mockSuccesfulJobFetch({ id: 1, status: 'done', log });
81+
await result.component.show({ id: 1, status: 'done', log: null }, false);
7082
const pre = result.container.querySelector('pre');
7183
expect(pre.classList.contains('highlight')).eq(false);
7284
expect(pre.innerHTML).eq(log);
7385
});
86+
87+
it('error while loading job for user', async () => {
88+
const result = render(JobLogsModal);
89+
fetch.mockResolvedValue({
90+
ok: false,
91+
json: () => new Promise((resolve) => resolve({ error: 'Something happened' }))
92+
});
93+
await result.component.show({ id: 1, status: 'done', log: null }, false);
94+
expect(result.queryByText(/Unable to fetch job/)).not.null;
95+
});
96+
97+
it('error while loading job for admin', async () => {
98+
const result = render(JobLogsModal);
99+
fetch.mockResolvedValue({
100+
ok: false,
101+
json: () => new Promise((resolve) => resolve({ error: 'Something happened' }))
102+
});
103+
await result.component.show({ id: 1, status: 'done', log: null }, true);
104+
expect(result.queryByText(/Unable to fetch job/)).not.null;
105+
});
74106
});
107+
108+
function mockSuccesfulJobFetch(job) {
109+
fetch.mockResolvedValue({
110+
ok: true,
111+
json: () => new Promise((resolve) => resolve(job))
112+
});
113+
}

__tests__/JobsList.test.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,27 +89,27 @@ describe('JobsList', () => {
8989
// Verify default sorting
9090
table = result.getByRole('table');
9191
expect(table.querySelectorAll('tbody tr:nth-child(1) td')[3].textContent).eq(
92-
'10/30/2023, 10:30:38 AM'
92+
'30/10/2023 10:30:38'
9393
);
9494
expect(table.querySelectorAll('tbody tr:nth-child(2) td')[3].textContent).eq(
95-
'10/30/2023, 10:15:38 AM'
95+
'30/10/2023 10:15:38'
9696
);
9797
expect(table.querySelectorAll('tbody tr:nth-child(3) td')[3].textContent).eq(
98-
'10/30/2023, 10:00:38 AM'
98+
'30/10/2023 10:00:38'
9999
);
100100

101101
// Sort by start date
102102
const startDateSorter = table.querySelector('thead th:nth-child(4)');
103103
await fireEvent.click(startDateSorter);
104104
table = result.getByRole('table');
105105
expect(table.querySelectorAll('tbody tr:nth-child(1) td')[3].textContent).eq(
106-
'10/30/2023, 10:00:38 AM'
106+
'30/10/2023 10:00:38'
107107
);
108108
expect(table.querySelectorAll('tbody tr:nth-child(2) td')[3].textContent).eq(
109-
'10/30/2023, 10:15:38 AM'
109+
'30/10/2023 10:15:38'
110110
);
111111
expect(table.querySelectorAll('tbody tr:nth-child(3) td')[3].textContent).eq(
112-
'10/30/2023, 10:30:38 AM'
112+
'30/10/2023 10:30:38'
113113
);
114114
});
115115

__tests__/TimestampCell.test.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { render } from '@testing-library/svelte';
3+
4+
import TimestampCell from '../src/lib/components/jobs/TimestampCell.svelte';
5+
6+
describe('TimestampCell', () => {
7+
it('handles null timestamp', async () => {
8+
const result = render(TimestampCell, {
9+
props: { timestamp: null }
10+
});
11+
expect(result.container.textContent).eq('-');
12+
});
13+
14+
it('handles empty timestamp', async () => {
15+
const result = render(TimestampCell, {
16+
props: { timestamp: '' }
17+
});
18+
expect(result.container.textContent).eq('-');
19+
});
20+
21+
it('handles valid timestamp', async () => {
22+
const result = render(TimestampCell, {
23+
props: { timestamp: '2024-02-09T10:35:56.237579+00:00' }
24+
});
25+
expect(result.container.textContent).eq('9/2/2024 11:35:56');
26+
});
27+
});

package-lock.json

Lines changed: 28 additions & 28 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111
"lint": "prettier --check . && eslint .",
1212
"format": "prettier --write .",
1313
"pre-commit": "lint-staged",
14-
"test": "TZ=Europe/Rome vitest"
14+
"test": "TZ=Europe/Rome LANG='it-IT' vitest"
1515
},
1616
"devDependencies": {
17-
"@playwright/test": "^1.40.0",
17+
"@playwright/test": "^1.41.2",
1818
"@sveltejs/adapter-auto": "^2.0.0",
1919
"@sveltejs/adapter-node": "^1.2.4",
2020
"@sveltejs/kit": "^1.15.7",

playwright.config.js

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,32 +19,47 @@ export default defineConfig({
1919
},
2020
dependencies: ['auth']
2121
},
22+
{
23+
name: 'create_fake_task',
24+
testMatch: /create_fake_task\.setup\.js/,
25+
use: {
26+
storageState: 'tests/.auth/user.json'
27+
},
28+
dependencies: ['collect_core_tasks', 'auth']
29+
},
2230
{
2331
name: 'chromium',
2432
use: {
2533
...devices['Desktop Chrome'],
2634
storageState: 'tests/.auth/user.json'
2735
},
28-
dependencies: ['collect_core_tasks']
36+
dependencies: ['create_fake_task']
2937
},
3038
{
3139
name: 'firefox',
3240
use: {
3341
...devices['Desktop Firefox'],
3442
storageState: 'tests/.auth/user.json'
3543
},
36-
dependencies: ['collect_core_tasks']
44+
dependencies: ['create_fake_task']
3745
}
3846
],
3947

4048
webServer: [
4149
{
42-
command: './tests/start-test-server.sh 1.4.3',
50+
command: './tests/start-test-server.sh 1.4.6',
4351
port: 8000,
4452
waitForPort: true,
4553
stdout: 'pipe',
4654
reuseExistingServer: !process.env.CI
4755
},
56+
{
57+
command: 'node ./tests/fake-job-server.js',
58+
port: 8080,
59+
waitForPort: true,
60+
stdout: 'pipe',
61+
reuseExistingServer: !process.env.CI
62+
},
4863
{
4964
command: 'npm run build && ORIGIN=http://localhost:5173 PORT=5173 node build',
5065
port: 5173,

0 commit comments

Comments
 (0)