Skip to content

Commit 5960d4d

Browse files
committed
refactor(e2e): moved project methods to fixture
1 parent 5881084 commit 5960d4d

File tree

11 files changed

+190
-108
lines changed

11 files changed

+190
-108
lines changed

e2e/tests/fixtures.ts

Lines changed: 86 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,99 @@
1-
import { test as base } from '@playwright/test';
1+
import { test as base } from "@playwright/test";
22

33
export const test = base.extend<{
44
login: (asAdmin: boolean) => Promise<void>;
5-
project: (role: 'owner' | 'manager' | 'task_runner' | 'guest', demo: boolean) => Promise<void>;
5+
project: {
6+
create: (
7+
role?: "owner" | "manager" | "task_runner" | "guest",
8+
demo?: boolean,
9+
name?: string
10+
) => Promise<string>;
11+
delete: () => Promise<void>;
12+
};
613
}>({
7-
814
login: async ({ page }, use) => {
915
await use(async (asAdmin: boolean) => {
10-
await page.goto('/auth/login');
11-
const username = asAdmin ? process.env.TEST_ADMIN_LOGIN : process.env.TEST_USER_LOGIN;
12-
if (!username) {
13-
throw new Error('TEST_ADMIN_LOGIN or TEST_USER_LOGIN is not set');
14-
}
15-
const password = asAdmin ? process.env.TEST_ADMIN_PASSWORD : process.env.TEST_USER_PASSWORD;
16-
if (!password) {
17-
throw new Error('TEST_ADMIN_PASSWORD or TEST_USER_PASSWORD is not set');
18-
}
19-
await page.getByTestId('auth-username').fill(username);
20-
await page.getByTestId('auth-password').fill(password);
21-
await page.getByTestId('auth-signin').click();
16+
await page.goto("/auth/login");
17+
const username = asAdmin
18+
? process.env.TEST_ADMIN_LOGIN
19+
: process.env.TEST_USER_LOGIN;
20+
if (!username) {
21+
throw new Error("TEST_ADMIN_LOGIN or TEST_USER_LOGIN is not set");
22+
}
23+
const password = asAdmin
24+
? process.env.TEST_ADMIN_PASSWORD
25+
: process.env.TEST_USER_PASSWORD;
26+
if (!password) {
27+
throw new Error("TEST_ADMIN_PASSWORD or TEST_USER_PASSWORD is not set");
28+
}
29+
await page.getByTestId("auth-username").fill(username);
30+
await page.getByTestId("auth-password").fill(password);
31+
await page.getByTestId("auth-signin").click();
2232
});
2333
},
2434

2535
project: async ({ page }, use) => {
26-
await use(async (role = 'owner', demo = false) => {
27-
await page.getByTestId('sidebar-currentProject').click();
28-
await page.getByTestId('sidebar-newProject').click();
29-
await page.getByTestId('newProject-name').fill('Test');
30-
await page.getByRole('dialog').getByText('Demo').click();
31-
await page.getByRole('dialog').getByRole('button', { name: 'Create' }).click();
36+
await use({
37+
/**
38+
* Create a new project.
39+
* @param role One of 'owner'|'manager'|'task_runner'|'guest'; defaults to 'owner'
40+
* @param demo Whether to enable the "Demo" flag; defaults to false
41+
* @param name Optional custom project name; if omitted, a timestamped name is generated
42+
* @returns The name of the newly created project
43+
*/
44+
create: async (role = "owner", demo = false, name?: string) => {
45+
const projectName = name ?? `test-${role}-${Date.now()}`;
46+
// open new-project dialog
47+
await page.getByTestId("sidebar-currentProject").click();
48+
await page.getByTestId("sidebar-newProject").click();
49+
// fill in details
50+
await page.getByTestId("newProject-name").fill(projectName);
51+
if (demo) {
52+
await page.getByRole("dialog").getByText("Demo").click();
53+
}
54+
// (optional) select role if your UI supports it:
55+
// await page.getByRole('combobox', { name: 'Role' }).selectOption(role);
56+
await page
57+
.getByRole("dialog")
58+
.getByRole("button", { name: "Create" })
59+
.click();
60+
61+
await page.getByText(`Project ${projectName} created`).waitFor();
62+
63+
// wait for the project to appear in the sidebar
64+
await page
65+
.getByTestId("sidebar-currentProject")
66+
.getByText(projectName)
67+
.waitFor();
68+
69+
await page.waitForTimeout(500);
70+
71+
return projectName;
72+
},
73+
74+
/**
75+
* Delete an existing project by name.
76+
* @param name The exact project name to delete
77+
*/
78+
delete: async () => {
79+
await page
80+
.getByTestId("taskLogDialog")
81+
.getByTestId("editDialog-close")
82+
.click();
83+
84+
await page.getByTestId("sidebar-dashboard").click();
85+
86+
await page.getByTestId("dashboard-settings").click();
87+
88+
await page.getByTestId("settings-deleteProject").click();
89+
90+
await page
91+
.getByRole("dialog")
92+
.getByRole("button", { name: "Yes" })
93+
.click();
94+
},
3295
});
33-
}
96+
},
3497
});
3598

36-
export { expect } from '@playwright/test';
99+
export { expect } from "@playwright/test";

e2e/tests/task.spec.ts

Lines changed: 71 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,92 @@
1-
import { test, expect } from './fixtures';
1+
import { test, expect } from "./fixtures";
22

3-
test('run task from demo project', async ({ page, login, project }) => {
4-
await login(true);
5-
await project('task_runner', true);
63

7-
await page.getByText('Project Test created').waitFor();
4+
test.describe("task running", () => {
5+
test.beforeEach(async ({ page, login, project }) => {
6+
7+
await login(true);
88

9-
await page.getByTestId('sidebar-templates').click();
10-
11-
await page.getByRole('link', { name: 'Build demo app' }).click();
9+
await project.create("task_runner", true);
1210

13-
await page.getByTestId('template-run').click();
11+
await page.getByTestId("sidebar-templates").click();
1412

15-
await page.getByTestId('newTaskDialog').getByRole('textbox', { name: 'Message (Optional)' }).fill('Test');
13+
await page.getByRole("link", { name: "Build demo app" }).click();
1614

17-
await page.getByTestId('newTaskDialog').getByTestId('editDialog-save').click();
15+
await page.getByTestId("template-run").click();
1816

19-
await page.getByTestId('task-rawLog').waitFor({timeout: 100000});
17+
await page
18+
.getByTestId("newTaskDialog")
19+
.getByRole("textbox", { name: "Message (Optional)" })
20+
.fill("Test");
2021

21-
await expect(page.getByTestId('task-status')).toHaveText('Success');
22-
});
22+
await page
23+
.getByTestId("newTaskDialog")
24+
.getByTestId("editDialog-save")
25+
.click();
2326

24-
test('stop task on waiting', async ({ page, login, project }) => {
25-
await login(true);
26-
await project('task_runner', true);
27+
test.setTimeout(90000);
28+
});
2729

28-
await page.getByText('Project Test created').waitFor();
30+
test.afterEach(async ({ project }) => {
31+
await project.delete();
32+
});
2933

30-
await page.getByTestId('sidebar-templates').click();
31-
32-
await page.getByRole('link', { name: 'Build demo app' }).click();
34+
test("run task from demo project", async ({ page }) => {
3335

34-
await page.getByTestId('template-run').click();
36+
await page.getByTestId("task-rawLog").waitFor({ timeout: 60000 });
3537

36-
await page.getByTestId('newTaskDialog').getByRole('textbox', { name: 'Message (Optional)' }).fill('Test');
38+
await expect(page.getByTestId("task-status")).toHaveText("Success");
39+
});
3740

38-
await page.getByTestId('newTaskDialog').getByTestId('editDialog-save').click();
3941

40-
await page.getByRole('dialog').getByRole('button', { name: 'Stop' }).click();
42+
test("stop task on waiting", async ({ page }) => {
4143

42-
await page.getByTestId('task-rawLog').waitFor();
44+
await page
45+
.getByRole("dialog")
46+
.getByRole("button", { name: "Stop" })
47+
.click();
4348

44-
await expect(page.getByTestId('task-status')).toHaveText('Stopped');
49+
await page.getByTestId("task-rawLog").waitFor({ timeout: 600000 });
4550

46-
});
51+
await expect(page.getByTestId("task-status")).toHaveText("Stopped");
4752

48-
test('stop task on cloning', async ({ page, login, project }) => {
49-
await login(true);
50-
await project('task_runner', true);
51-
52-
await page.getByText('Project Test created').waitFor();
53-
54-
await page.getByTestId('sidebar-templates').click();
55-
56-
await page.getByRole('link', { name: 'Build demo app' }).click();
57-
58-
await page.getByTestId('template-run').click();
59-
60-
await page.getByTestId('newTaskDialog').getByRole('textbox', { name: 'Message (Optional)' }).fill('Test');
61-
62-
await page.getByTestId('newTaskDialog').getByTestId('editDialog-save').click();
63-
64-
await page.getByRole('dialog').getByText('Get current commit hash').waitFor();
65-
66-
await page.getByRole('dialog').getByRole('button', { name: 'Stop' }).click();
67-
68-
await page.getByTestId('task-rawLog').waitFor();
69-
70-
await expect(page.getByTestId('task-status')).toHaveText('Stopped');
71-
7253
});
7354

74-
test('stop task on running', async ({ page, login, project }) => {
75-
await login(true);
76-
await project('task_runner', true);
77-
78-
await page.getByText('Project Test created').waitFor();
79-
80-
await page.getByTestId('sidebar-templates').click();
81-
82-
await page.getByRole('link', { name: 'Build demo app' }).click();
83-
84-
await page.getByTestId('template-run').click();
85-
86-
await page.getByTestId('newTaskDialog').getByRole('textbox', { name: 'Message (Optional)' }).fill('Test');
87-
88-
await page.getByTestId('newTaskDialog').getByTestId('editDialog-save').click();
89-
90-
await page.getByRole('dialog').getByText('TASK [Gathering Facts] *********************************************************').waitFor();
91-
92-
await page.getByRole('dialog').getByRole('button', { name: 'Stop' }).click();
93-
94-
await page.getByTestId('task-rawLog').waitFor();
95-
96-
await expect(page.getByTestId('task-status')).toHaveText('Stopped');
97-
98-
});
55+
test("stop task on cloning", async ({ page }) => {
56+
57+
await page
58+
.getByRole("dialog")
59+
.getByText("Get current commit hash")
60+
.waitFor();
61+
62+
await page
63+
.getByRole("dialog")
64+
.getByRole("button", { name: "Stop" })
65+
.click();
66+
67+
await page.getByTestId("task-rawLog").waitFor({ timeout: 60000 });
68+
69+
await expect(page.getByTestId("task-status")).toHaveText("Stopped");
70+
71+
});
72+
73+
test("stop task on running", async ({ page }) => {
74+
75+
await page
76+
.getByRole("dialog")
77+
.getByText(
78+
"TASK [Gathering Facts] *********************************************************"
79+
)
80+
.waitFor({ timeout: 100000 });
81+
82+
await page
83+
.getByRole("dialog")
84+
.getByRole("button", { name: "Stop" })
85+
.click();
86+
87+
await page.getByTestId("task-rawLog").waitFor({ timeout: 60000 });
88+
89+
await expect(page.getByTestId("task-status")).toHaveText("Stopped");
90+
91+
});
92+
});

services/runners/running_job.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,6 @@ func (p *runningJob) logPipe(reader io.Reader) {
104104

105105
if scanner.Err() != nil && scanner.Err().Error() != "EOF" {
106106
//don't panic on these errors, sometimes it throws not dangerous "read |0: file already closed" error
107-
util.LogWarningF(scanner.Err(), log.Fields{"error": "Failed to read TaskRunner output"})
107+
util.LogDebugF(scanner.Err(), log.Fields{"error": "Failed to read TaskRunner output"})
108108
}
109109
}

services/tasks/TaskPool.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,13 @@ func (p *TaskPool) blocks(t *TaskRunner) bool {
217217
return false
218218
}
219219

220-
return proj.MaxParallelTasks > 0 && len(p.activeProj[t.Task.ProjectID]) >= proj.MaxParallelTasks
220+
res := proj.MaxParallelTasks > 0 && len(p.activeProj[t.Task.ProjectID]) >= proj.MaxParallelTasks
221+
222+
if res {
223+
return true
224+
}
225+
226+
return res
221227
}
222228

223229
func CreateTaskPool(store db.Store) TaskPool {

services/tasks/TaskRunner.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,9 @@ func (t *TaskRunner) createTaskEvent() {
125125
_, err := t.pool.store.CreateEvent(event)
126126

127127
if err != nil {
128-
t.panicOnError(err, "Fatal error inserting an event")
128+
msg := "Fatal error inserting an event"
129+
t.Log(msg)
130+
log.WithError(err).Error(msg)
129131
}
130132
}
131133

services/tasks/TaskRunner_logging.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,12 @@ func (t *TaskRunner) SetStatus(status task_logger.TaskStatus) {
130130
}
131131

132132
func (t *TaskRunner) panicOnError(err error, msg string) {
133-
if err != nil {
134-
t.Log(msg)
135-
util.LogPanicF(err, log.Fields{"error": msg})
133+
if err == nil {
134+
return
136135
}
136+
137+
t.Log(msg)
138+
util.LogPanicF(err, log.Fields{"error": msg})
137139
}
138140

139141
func (t *TaskRunner) logPipe(reader io.Reader) {
@@ -159,6 +161,6 @@ func (t *TaskRunner) logPipe(reader io.Reader) {
159161
close(linesCh)
160162

161163
if scanner.Err() != nil && scanner.Err().Error() != "EOF" {
162-
util.LogWarningF(scanner.Err(), log.Fields{"error": "Failed to read TaskRunner output"})
164+
util.LogDebugF(scanner.Err(), log.Fields{"error": "Failed to read TaskRunner output"})
163165
}
164166
}

util/errorLogging.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ func LogWarning(err error) {
99
LogWarningF(err, log.Fields{"level": "Warn"})
1010
}
1111

12+
// LogDebugF logs a debug with added field context if error
13+
func LogDebugF(err error, fields log.Fields) {
14+
if err != nil {
15+
log.WithFields(fields).Debug(err.Error())
16+
}
17+
}
18+
1219
// LogWarningF logs a warning with added field context if error
1320
func LogWarningF(err error, fields log.Fields) {
1421
if err != nil {

web/src/App.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
name="TaskLogDialog"
6363
@close="onTaskLogDialogClosed()"
6464
no-body-paddings
65+
test-id="taskLogDialog"
6566
>
6667
<template v-slot:title={}>
6768
<div class="text-truncate" style="max-width: calc(100% - 36px);">

0 commit comments

Comments
 (0)