mirror of
https://github.com/SecurityBrewery/catalyst.git
synced 2026-01-09 07:43:08 +01:00
refactor: remove pocketbase (#1138)
This commit is contained in:
1
ui/tests/assets/file.txt
Normal file
1
ui/tests/assets/file.txt
Normal file
@@ -0,0 +1 @@
|
||||
hello world
|
||||
24
ui/tests/demo/demo.spec.ts
Normal file
24
ui/tests/demo/demo.spec.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { expect } from '@playwright/test'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { login, test, createTicket } from '../e2e/util'
|
||||
|
||||
// Test that file upload is disabled in demo mode
|
||||
|
||||
test('file upload is disabled', async ({ page }) => {
|
||||
await login(page)
|
||||
const ticketName = `playwright-${randomUUID()}`
|
||||
await createTicket(page, ticketName)
|
||||
await expect(page.getByText('Cannot upload files in demo mode')).toBeVisible()
|
||||
})
|
||||
|
||||
// Test that reaction creation is disabled in demo mode
|
||||
|
||||
test('reaction creation is disabled', async ({ page }) => {
|
||||
await login(page)
|
||||
await page.goto('reactions')
|
||||
await page.getByRole('button', { name: 'New Reaction' }).click()
|
||||
await page.waitForURL('**/reactions/new')
|
||||
const saveBtn = page.getByRole('button', { name: 'Save' }).last()
|
||||
await expect(saveBtn).toBeDisabled()
|
||||
await expect(page.getByText('Reactions cannot be created or edited in demo mode')).toBeVisible()
|
||||
})
|
||||
36
ui/tests/e2e/auth.spec.ts
Normal file
36
ui/tests/e2e/auth.spec.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { expect } from '@playwright/test'
|
||||
import { login, test } from './util'
|
||||
|
||||
// Verify that login stores a token and grants API access
|
||||
|
||||
test('login grants api access', async ({ page }) => {
|
||||
await login(page)
|
||||
await expect(page).toHaveURL(/.*\/dashboard/)
|
||||
|
||||
const token = await page.evaluate(() => localStorage.getItem('token'))
|
||||
expect(token).toBeTruthy()
|
||||
|
||||
const response = await page.request.get('/auth/user', {
|
||||
headers: { Authorization: `Bearer ${token}` }
|
||||
})
|
||||
expect(response.status()).toBe(200)
|
||||
const data = await response.json()
|
||||
expect(data.user.email).toBe('admin@catalyst-soar.com')
|
||||
})
|
||||
|
||||
// Verify that logout clears the token and api requests fail without it
|
||||
|
||||
test('logout denies api access', async ({ page }) => {
|
||||
await login(page)
|
||||
const button = page.getByRole('button', { name: /admin/i })
|
||||
await button.click()
|
||||
await page.getByRole('menuitem', { name: 'Log out' }).click()
|
||||
await page.waitForURL('**/login')
|
||||
|
||||
const token = await page.evaluate(() => localStorage.getItem('token'))
|
||||
expect(token).toBe('')
|
||||
|
||||
const response = await page.request.get('/auth/user')
|
||||
const data = await response.json()
|
||||
expect(data).toBeNull()
|
||||
})
|
||||
54
ui/tests/e2e/comments.spec.ts
Normal file
54
ui/tests/e2e/comments.spec.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { expect } from '@playwright/test'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { login, test, createTicket, createComment } from './util'
|
||||
|
||||
test('can create a comment', async ({ page }) => {
|
||||
await login(page)
|
||||
const ticketName = `playwright-${randomUUID()}`
|
||||
await createTicket(page, ticketName)
|
||||
const message = `comment-${randomUUID()}`
|
||||
await createComment(page, message)
|
||||
})
|
||||
|
||||
test.describe('update a comment', () => {
|
||||
const updates = [
|
||||
{
|
||||
field: 'message',
|
||||
update: async (page) => {
|
||||
await page.getByRole('tab', { name: 'Comments' }).click()
|
||||
await page.getByRole('button', { name: 'More' }).click()
|
||||
await page.getByRole('menuitem', { name: 'Edit' }).click()
|
||||
await page.locator('textarea').nth(1).fill('Updated Comment')
|
||||
await page.getByRole('button', { name: 'Save' }).click()
|
||||
},
|
||||
assert: async (page) => {
|
||||
await expect(page.getByText('Updated Comment')).toBeVisible()
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
for (const { field, update, assert } of updates) {
|
||||
test(`can update ${field}`, async ({ page }) => {
|
||||
await login(page)
|
||||
const ticketName = `playwright-${randomUUID()}`
|
||||
await createTicket(page, ticketName)
|
||||
const message = `comment-${randomUUID()}`
|
||||
await createComment(page, message)
|
||||
await update(page, message)
|
||||
await assert(page)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
test('can delete a comment', async ({ page }) => {
|
||||
await login(page)
|
||||
const ticketName = `playwright-${randomUUID()}`
|
||||
await createTicket(page, ticketName)
|
||||
const message = `comment-${randomUUID()}`
|
||||
await createComment(page, message)
|
||||
await page.getByRole('tab', { name: 'Comments' }).click()
|
||||
await page.getByRole('button', { name: 'More' }).click()
|
||||
await page.getByRole('menuitem', { name: 'Delete' }).click()
|
||||
await page.getByRole('dialog').getByRole('button', { name: 'Delete' }).click()
|
||||
await expect(page.getByText(message)).toHaveCount(0)
|
||||
})
|
||||
7
ui/tests/e2e/dashboard.spec.ts
Normal file
7
ui/tests/e2e/dashboard.spec.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { expect } from '@playwright/test'
|
||||
import { login, test } from './util'
|
||||
|
||||
test('dashboard title is visible', async ({ page }) => {
|
||||
await login(page)
|
||||
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible()
|
||||
})
|
||||
26
ui/tests/e2e/files.spec.ts
Normal file
26
ui/tests/e2e/files.spec.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { expect } from '@playwright/test'
|
||||
import { randomUUID } from 'crypto'
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { login, test, createTicket, uploadFile } from './util'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
const filePath = path.join(__dirname, '../assets/file.txt')
|
||||
|
||||
test('can upload a file', async ({ page }) => {
|
||||
await login(page)
|
||||
const ticketName = `playwright-${randomUUID()}`
|
||||
await createTicket(page, ticketName)
|
||||
await uploadFile(page, filePath)
|
||||
})
|
||||
|
||||
test('can delete a file', async ({ page }) => {
|
||||
await login(page)
|
||||
const ticketName = `playwright-${randomUUID()}`
|
||||
await createTicket(page, ticketName)
|
||||
await uploadFile(page, filePath)
|
||||
await page.locator('button', { hasText: 'Delete File' }).click()
|
||||
await page.getByRole('dialog').getByRole('button', { name: 'Delete' }).click()
|
||||
await expect(page.getByText(path.basename(filePath))).toHaveCount(0)
|
||||
})
|
||||
|
||||
73
ui/tests/e2e/groups.spec.ts
Normal file
73
ui/tests/e2e/groups.spec.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { expect } from '@playwright/test'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { login, test } from './util'
|
||||
|
||||
const createGroup = async (page, name: string) => {
|
||||
await page.goto('groups')
|
||||
await page.getByRole('button', { name: 'New Group' }).click()
|
||||
await page.waitForURL('**/groups/new')
|
||||
await page.locator('#name').fill(name)
|
||||
await page.getByRole('combobox', { name: 'Permissions' }).click()
|
||||
await page.getByRole('option', { name: 'ticket:read' }).click()
|
||||
const saveBtn = page.getByRole('button', { name: 'Save' }).last()
|
||||
await expect(saveBtn).toBeEnabled()
|
||||
await saveBtn.click()
|
||||
await page.waitForURL('**/groups/g*')
|
||||
}
|
||||
|
||||
test('groups list shows existing groups', async ({ page }) => {
|
||||
await login(page)
|
||||
await page.goto('groups')
|
||||
await expect(page.getByRole('heading', { name: 'Groups' })).toBeVisible()
|
||||
})
|
||||
|
||||
test('can create a group', async ({ page }) => {
|
||||
await login(page)
|
||||
const name = `playwright-${randomUUID()}`
|
||||
await createGroup(page, name)
|
||||
await expect(page.locator('#name')).toHaveValue(name)
|
||||
})
|
||||
|
||||
test.describe('update a group', () => {
|
||||
const updates = [
|
||||
{ field: 'name', selector: '#name', value: 'Updated Group' },
|
||||
// { field: 'permissions', selector: '#permissions', value: 'reaction:write' },
|
||||
]
|
||||
|
||||
for (const { field, selector, value } of updates) {
|
||||
test(`can update ${field}`, async ({ page }) => {
|
||||
await login(page)
|
||||
const name = `playwright-${randomUUID()}`
|
||||
await createGroup(page, name)
|
||||
await page.waitForSelector(selector)
|
||||
await page.locator(selector).fill(value)
|
||||
const saveBtn = page.getByRole('button', { name: 'Save' }).last()
|
||||
await expect(saveBtn).toBeEnabled()
|
||||
await saveBtn.click()
|
||||
await expect(page.locator(selector)).toHaveValue(value)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
test('can add a permission', async ({ page }) => {
|
||||
await login(page)
|
||||
const name = `playwright-${randomUUID()}`
|
||||
await createGroup(page, name)
|
||||
await page.getByRole('combobox', { name: 'Permissions' }).click()
|
||||
await page.getByRole('option', { name: 'reaction:write' }).click()
|
||||
const saveBtn = page.getByRole('button', { name: 'Save' }).last()
|
||||
await expect(saveBtn).toBeEnabled()
|
||||
await saveBtn.click()
|
||||
await page.waitForURL('**/groups/*')
|
||||
await expect(page.locator('#permissions')).toHaveText('Permissionsticket:readreaction:write')
|
||||
})
|
||||
|
||||
test('can delete a group', async ({ page }) => {
|
||||
await login(page)
|
||||
const name = `playwright-${randomUUID()}`
|
||||
await createGroup(page, name)
|
||||
await page.getByRole('button', { name: 'Delete Group' }).click()
|
||||
await page.getByRole('dialog').getByRole('button', { name: 'Delete' }).click()
|
||||
await page.waitForURL('**/groups')
|
||||
await expect(page.locator(`text=${name}`)).toHaveCount(0)
|
||||
})
|
||||
22
ui/tests/e2e/links.spec.ts
Normal file
22
ui/tests/e2e/links.spec.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { expect } from '@playwright/test'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { login, test, createTicket, createLink } from './util'
|
||||
|
||||
test('can create a link', async ({ page }) => {
|
||||
await login(page)
|
||||
const ticketName = `playwright-${randomUUID()}`
|
||||
await createTicket(page, ticketName)
|
||||
const linkName = `link-${randomUUID()}`
|
||||
await createLink(page, linkName, 'https://example.com')
|
||||
})
|
||||
|
||||
test('can delete a link', async ({ page }) => {
|
||||
await login(page)
|
||||
const ticketName = `playwright-${randomUUID()}`
|
||||
await createTicket(page, ticketName)
|
||||
const linkName = `link-${randomUUID()}`
|
||||
await createLink(page, linkName, 'https://example.com')
|
||||
await page.locator('button', { hasText: 'Delete Link' }).click()
|
||||
await page.getByRole('dialog').getByRole('button', { name: 'Delete' }).click()
|
||||
await expect(page.getByText(linkName)).toHaveCount(0)
|
||||
})
|
||||
103
ui/tests/e2e/reactions.spec.ts
Normal file
103
ui/tests/e2e/reactions.spec.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { expect } from '@playwright/test'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { login, test } from './util'
|
||||
|
||||
const createReaction = async (page, name: string) => {
|
||||
await page.goto('reactions')
|
||||
await page.getByRole('button', { name: 'New Reaction' }).click()
|
||||
await page.waitForURL('**/reactions/new')
|
||||
await page.locator('#name').fill(name)
|
||||
await page.locator('#trigger').selectOption('Schedule')
|
||||
await page.locator('#expression').fill('* * * * *')
|
||||
await page.locator('#action').selectOption('Python')
|
||||
await page.locator('#script').fill('print("Hello, world!")')
|
||||
const saveBtn = page.getByRole('button', { name: 'Save' }).last()
|
||||
await expect(saveBtn).toBeEnabled()
|
||||
await saveBtn.click()
|
||||
await page.waitForURL('**/reactions/r*')
|
||||
}
|
||||
|
||||
test('reactions list shows existing reactions', async ({ page }) => {
|
||||
await login(page)
|
||||
await page.goto('reactions')
|
||||
await expect(page.getByRole('heading', { name: 'Reactions' })).toBeVisible()
|
||||
})
|
||||
|
||||
test('can create a reaction', async ({ page }) => {
|
||||
await login(page)
|
||||
const name = `playwright-${randomUUID()}`
|
||||
await createReaction(page, name)
|
||||
await expect(page.locator('#name')).toHaveValue(name)
|
||||
await expect(page.locator('#trigger')).toHaveValue('schedule')
|
||||
await expect(page.locator('#expression')).toHaveValue('* * * * *')
|
||||
await expect(page.locator('#action')).toHaveValue('python')
|
||||
await expect(page.locator('#script')).toHaveValue('print("Hello, world!")')
|
||||
})
|
||||
|
||||
test.describe('update a reaction', () => {
|
||||
const updates = [
|
||||
{
|
||||
field: 'name',
|
||||
update: async (page) => {
|
||||
await page.waitForSelector('#name')
|
||||
await page.locator('#name').fill("Updated Reaction")
|
||||
},
|
||||
selector: '#name',
|
||||
value: 'Updated Reaction'
|
||||
},
|
||||
{
|
||||
field: 'trigger',
|
||||
update: async (page) => {
|
||||
await page.waitForSelector('#trigger')
|
||||
await page.locator('button').filter({ hasText: 'Schedule' }).click()
|
||||
await page.getByRole('option', { name: 'HTTP / Webhook' }).click()
|
||||
await page.locator('#path').fill('webhook')
|
||||
},
|
||||
selector: '#trigger',
|
||||
value: 'webhook'
|
||||
},
|
||||
{
|
||||
field: 'action',
|
||||
update: async (page) => {
|
||||
await page.waitForSelector('#action')
|
||||
await page.locator('button').filter({ hasText: 'Python' }).click()
|
||||
await page.getByRole('option', { name: 'HTTP / Webhook' }).click()
|
||||
await page.locator('#url').fill('https://example.com')
|
||||
},
|
||||
selector: '#action',
|
||||
value: 'webhook'
|
||||
},
|
||||
{
|
||||
field: 'script',
|
||||
update: async (page) => {
|
||||
await page.waitForSelector('#script')
|
||||
await page.locator('#script').fill('pass')
|
||||
},
|
||||
selector: '#script',
|
||||
value: 'pass'
|
||||
},
|
||||
]
|
||||
|
||||
for (const { field, update, selector, value } of updates) {
|
||||
test(`can update ${field}`, async ({ page }) => {
|
||||
await login(page)
|
||||
const name = `playwright-${randomUUID()}`
|
||||
await createReaction(page, name)
|
||||
await update(page)
|
||||
const saveBtn = page.getByRole('button', { name: 'Save' }).last()
|
||||
await expect(saveBtn).toBeEnabled()
|
||||
await saveBtn.click()
|
||||
await expect(page.locator(selector)).toHaveValue(value)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
test('can delete a reaction', async ({ page }) => {
|
||||
await login(page)
|
||||
const name = `playwright-${randomUUID()}`
|
||||
await createReaction(page, name)
|
||||
await page.getByRole('button', { name: 'Delete Reaction' }).click()
|
||||
await page.getByRole('dialog').getByRole('button', { name: 'Delete' }).click()
|
||||
await page.waitForURL('**/reactions')
|
||||
await expect(page.locator(`text=${name}`)).toHaveCount(0)
|
||||
})
|
||||
54
ui/tests/e2e/settings.spec.ts
Normal file
54
ui/tests/e2e/settings.spec.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { login, test } from './util'
|
||||
import { expect } from '@playwright/test'
|
||||
|
||||
const goToSettings = async (page) => {
|
||||
await page.goto('settings')
|
||||
await expect(page.getByRole('heading', { name: 'Settings' })).toBeVisible()
|
||||
}
|
||||
|
||||
test('settings page shows existing settings', async ({ page }) => {
|
||||
await login(page)
|
||||
await goToSettings(page)
|
||||
await expect(page.locator('#meta\\.appName')).toHaveValue('Catalyst')
|
||||
})
|
||||
|
||||
const updates = [
|
||||
{ field: 'app name', selector: '#meta\\.appName', value: () => `Catalyst-${Date.now()}` },
|
||||
// {
|
||||
// field: 'app url',
|
||||
// selector: '#meta\\.appUrl',
|
||||
// value: () => `https://catalyst-${Date.now()}.example.com`
|
||||
// },
|
||||
{ field: 'sender name', selector: '#meta\\.senderName', value: () => `Catalyst-${Date.now()}` },
|
||||
{
|
||||
field: 'sender address',
|
||||
selector: '#meta\\.senderAddress',
|
||||
value: () => `catalyst-${Date.now()}@example.com`
|
||||
}
|
||||
]
|
||||
|
||||
test.describe('update settings', () => {
|
||||
for (const { field, selector, value } of updates) {
|
||||
test(`can update ${field}`, async ({ page }) => {
|
||||
await login(page)
|
||||
await goToSettings(page)
|
||||
const v = value()
|
||||
await page.locator(selector).fill(v)
|
||||
const saveBtn = page.getByRole('button', { name: 'Save' }).last()
|
||||
await expect(saveBtn).toBeEnabled()
|
||||
await saveBtn.click()
|
||||
await expect(page.locator(selector)).toHaveValue(v)
|
||||
})
|
||||
}
|
||||
|
||||
test('can enable smtp', async ({ page }) => {
|
||||
await login(page)
|
||||
await goToSettings(page)
|
||||
const smtpSwitch = page.getByRole('switch').first()
|
||||
await smtpSwitch.click()
|
||||
const saveBtn = page.getByRole('button', { name: 'Save' }).last()
|
||||
await expect(saveBtn).toBeEnabled()
|
||||
await saveBtn.click()
|
||||
await expect(smtpSwitch).toHaveAttribute('data-state', 'checked')
|
||||
})
|
||||
})
|
||||
66
ui/tests/e2e/tasks.spec.ts
Normal file
66
ui/tests/e2e/tasks.spec.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { expect } from '@playwright/test'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { login, test, createTicket, createTask } from './util'
|
||||
|
||||
test('can create a task', async ({ page }) => {
|
||||
await login(page)
|
||||
const ticketName = `playwright-${randomUUID()}`
|
||||
await createTicket(page, ticketName)
|
||||
const taskName = `task-${randomUUID()}`
|
||||
await createTask(page, taskName, false)
|
||||
})
|
||||
|
||||
test.describe('update a task', () => {
|
||||
const updates = [
|
||||
{
|
||||
field: 'name',
|
||||
update: async (page, taskName: string) => {
|
||||
await page.getByText("Toggle Sidebar").click()
|
||||
|
||||
await page.getByRole('tab', { name: 'Tasks' }).click()
|
||||
await page.getByText(taskName).click()
|
||||
await page.getByRole('tabpanel', { name: 'Tasks' }).getByRole('textbox').fill('Updated Task')
|
||||
await page.keyboard.press('Enter')
|
||||
},
|
||||
assert: async (page) => {
|
||||
await expect(page.getByText('Updated Task')).toBeVisible()
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
update: async (page) => {
|
||||
await page.getByRole('tab', { name: 'Tasks' }).click()
|
||||
const cb = page.getByRole('checkbox').first()
|
||||
await cb.click()
|
||||
},
|
||||
assert: async (page) => {
|
||||
const cb = page.getByRole('checkbox').first()
|
||||
await expect(cb).toHaveAttribute('data-state', 'checked')
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
for (const { field, update, assert } of updates) {
|
||||
test(`can update ${field}`, async ({ page }) => {
|
||||
await login(page)
|
||||
const ticketName = `playwright-${randomUUID()}`
|
||||
await createTicket(page, ticketName)
|
||||
const taskName = `task-${randomUUID()}`
|
||||
await createTask(page, taskName, false)
|
||||
await update(page, taskName)
|
||||
await assert(page)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
test('can delete a task', async ({ page }) => {
|
||||
await login(page)
|
||||
const ticketName = `playwright-${randomUUID()}`
|
||||
await createTicket(page, ticketName)
|
||||
const taskName = `task-${randomUUID()}`
|
||||
await createTask(page, taskName, false)
|
||||
await page.getByRole('tab', { name: 'Tasks' }).click()
|
||||
await page.locator('button', { hasText: 'Delete Task' }).click()
|
||||
await page.getByRole('dialog').getByRole('button', { name: 'Delete' }).click()
|
||||
await expect(page.getByText(taskName)).toHaveCount(0)
|
||||
})
|
||||
55
ui/tests/e2e/tickets.spec.ts
Normal file
55
ui/tests/e2e/tickets.spec.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { expect } from '@playwright/test'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { login, test, createTicket } from './util'
|
||||
|
||||
test('can create a ticket', async ({ page }) => {
|
||||
await login(page)
|
||||
const name = `playwright-${randomUUID()}`
|
||||
await createTicket(page, name)
|
||||
await expect(page.locator('#app #name').getByText(name)).toBeVisible()
|
||||
})
|
||||
|
||||
test.describe('update a ticket', () => {
|
||||
const updates = [
|
||||
{
|
||||
field: 'description',
|
||||
update: async (page) => {
|
||||
await page.getByRole('button', { name: 'Edit' }).click()
|
||||
await page.getByRole('application').getByRole('textbox').fill('Updated description')
|
||||
await page.getByRole('button', { name: 'Save' }).last().click()
|
||||
},
|
||||
assert: async (page) => {
|
||||
await expect(page.getByText('Updated description')).toBeVisible()
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'severity',
|
||||
update: async (page) => {
|
||||
await page.locator('#app #severity').selectOption('High')
|
||||
},
|
||||
assert: async (page) => {
|
||||
await expect(page.locator('button').filter({ hasText: 'High' })).toBeVisible()
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
for (const { field, update, assert } of updates) {
|
||||
test(`can update ${field}`, async ({ page }) => {
|
||||
await login(page)
|
||||
const name = `playwright-${randomUUID()}`
|
||||
await createTicket(page, name)
|
||||
await update(page)
|
||||
await assert(page)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
test('can delete a ticket', async ({ page }) => {
|
||||
await login(page)
|
||||
const name = `playwright-${randomUUID()}`
|
||||
await createTicket(page, name)
|
||||
await page.getByRole('button', { name: 'Delete Ticket' }).click()
|
||||
await page.getByRole('dialog').getByRole('button', { name: 'Delete' }).click()
|
||||
await page.waitForURL('**/tickets/incident')
|
||||
await expect(page.locator(`text=${name}`)).toHaveCount(0)
|
||||
})
|
||||
40
ui/tests/e2e/timeline.spec.ts
Normal file
40
ui/tests/e2e/timeline.spec.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { expect } from '@playwright/test'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { login, test, createTicket, createTimeline } from './util'
|
||||
|
||||
test('can create a timeline item', async ({ page }) => {
|
||||
await login(page)
|
||||
const ticketName = `playwright-${randomUUID()}`
|
||||
await createTicket(page, ticketName)
|
||||
const msg = `timeline-${randomUUID()}`
|
||||
await createTimeline(page, msg)
|
||||
})
|
||||
|
||||
test.describe('update a timeline item', () => {
|
||||
test('can update message', async ({ page }) => {
|
||||
await login(page)
|
||||
const ticketName = `playwright-${randomUUID()}`
|
||||
await createTicket(page, ticketName)
|
||||
const msg = `timeline-${randomUUID()}`
|
||||
await createTimeline(page, msg)
|
||||
await page.getByRole('tab', { name: 'Timeline' }).click()
|
||||
await page.getByRole('button', { name: 'More' }).click()
|
||||
await page.getByRole('menuitem', { name: 'Edit' }).click()
|
||||
await page.locator('textarea').nth(1).fill('Updated Timeline')
|
||||
await page.getByRole('button', { name: 'Save' }).click()
|
||||
await expect(page.getByText('Updated Timeline')).toBeVisible()
|
||||
})
|
||||
})
|
||||
|
||||
test('can delete a timeline item', async ({ page }) => {
|
||||
await login(page)
|
||||
const ticketName = `playwright-${randomUUID()}`
|
||||
await createTicket(page, ticketName)
|
||||
const msg = `timeline-${randomUUID()}`
|
||||
await createTimeline(page, msg)
|
||||
await page.getByRole('tab', { name: 'Timeline' }).click()
|
||||
await page.getByRole('button', { name: 'More' }).click()
|
||||
await page.getByRole('menuitem', { name: 'Delete' }).click()
|
||||
await page.getByRole('dialog').getByRole('button', { name: 'Delete' }).click()
|
||||
await expect(page.getByText(msg)).toHaveCount(0)
|
||||
})
|
||||
67
ui/tests/e2e/types.spec.ts
Normal file
67
ui/tests/e2e/types.spec.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { expect } from '@playwright/test'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { login, test } from './util'
|
||||
|
||||
const createType = async (page, name: string) => {
|
||||
await page.goto('types')
|
||||
await page.getByRole('button', { name: 'New Type' }).click()
|
||||
await page.waitForURL('**/types/new')
|
||||
await page.locator('#singular').fill(name)
|
||||
await page.locator('#plural').fill(`${name}s`)
|
||||
await page.locator('#icon input').fill('Bug')
|
||||
await page.locator('#schema').fill('{}')
|
||||
const saveBtn = page.getByRole('button', { name: 'Save' }).last()
|
||||
await expect(saveBtn).toBeEnabled()
|
||||
await saveBtn.click()
|
||||
await page.waitForURL('**/types/y*')
|
||||
}
|
||||
|
||||
test('types list shows incident', async ({ page }) => {
|
||||
await login(page)
|
||||
await page.goto('types')
|
||||
await expect(page.getByRole('heading', { name: 'Types' })).toBeVisible()
|
||||
await expect(page.getByText('Incident', { exact: true })).toBeVisible()
|
||||
})
|
||||
|
||||
test('can create a type', async ({ page }) => {
|
||||
await login(page)
|
||||
const name = `Playwright-${randomUUID()}`
|
||||
await createType(page, name)
|
||||
await expect(page.locator('#singular')).toHaveValue(name)
|
||||
await expect(page.locator('#plural')).toHaveValue(`${name}s`)
|
||||
await expect(page.locator('#icon input')).toHaveValue('Bug')
|
||||
await expect(page.locator('#schema')).toHaveValue('{}')
|
||||
})
|
||||
|
||||
test.describe('update a type', () => {
|
||||
const updates = [
|
||||
{ field: 'singular', selector: '#singular', value: 'UpdatedSingular' },
|
||||
{ field: 'plural', selector: '#plural', value: 'UpdatedPlural' },
|
||||
{ field: 'icon', selector: '#icon input', value: 'Activity' },
|
||||
{ field: 'schema', selector: '#schema', value: '{"foo":"bar"}' },
|
||||
]
|
||||
|
||||
for (const { field, selector, value } of updates) {
|
||||
test(`can update ${field}`, async ({ page }) => {
|
||||
await login(page)
|
||||
const name = `Playwright-${randomUUID()}`
|
||||
await createType(page, name)
|
||||
await page.waitForSelector(selector)
|
||||
await page.locator(selector).fill(value)
|
||||
const saveBtn = page.getByRole('button', { name: 'Save' }).last()
|
||||
await expect(saveBtn).toBeEnabled()
|
||||
await saveBtn.click()
|
||||
await expect(page.locator(selector)).toHaveValue(value)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
test('can delete a type', async ({ page }) => {
|
||||
await login(page)
|
||||
const name = `Playwright-${randomUUID()}`
|
||||
await createType(page, name)
|
||||
await page.getByRole('button', { name: 'Delete Type' }).click()
|
||||
await page.getByRole('dialog').getByRole('button', { name: 'Delete' }).click()
|
||||
await page.waitForURL('**/types')
|
||||
await expect(page.locator(`text=${name}`)).toHaveCount(0)
|
||||
})
|
||||
82
ui/tests/e2e/users.spec.ts
Normal file
82
ui/tests/e2e/users.spec.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { expect } from '@playwright/test'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { login, test } from './util'
|
||||
|
||||
const createUser = async (page, username: string) => {
|
||||
await page.goto('users')
|
||||
await page.getByRole('button', { name: 'New User' }).click()
|
||||
await page.waitForURL('**/users/new')
|
||||
await page.locator('#username').fill(username)
|
||||
await page.locator('#email').fill(`${username}@example.com`)
|
||||
await page.locator('#name').fill(username)
|
||||
const saveBtn = page.getByRole('button', { name: 'Save' }).last()
|
||||
await expect(saveBtn).toBeEnabled()
|
||||
await saveBtn.click()
|
||||
await page.waitForURL('**/users/u*')
|
||||
}
|
||||
|
||||
test('users list shows existing users', async ({ page }) => {
|
||||
await login(page)
|
||||
await page.goto('users')
|
||||
await expect(page.getByRole('heading', { name: 'Users' })).toBeVisible()
|
||||
await expect(page.getByText('admin', { exact: true })).toBeVisible()
|
||||
})
|
||||
|
||||
test('can create a user', async ({ page }) => {
|
||||
await login(page)
|
||||
const username = `playwright-${randomUUID()}`
|
||||
await createUser(page, username)
|
||||
await expect(page.locator('#username')).toHaveValue(username)
|
||||
})
|
||||
|
||||
test.describe('update a user', () => {
|
||||
const updates = [
|
||||
{
|
||||
field: 'email',
|
||||
selector: '#email',
|
||||
value: 'updated@example.com'
|
||||
},
|
||||
{
|
||||
field: 'name',
|
||||
selector: '#name',
|
||||
value: 'Updated Name'
|
||||
}
|
||||
]
|
||||
|
||||
for (const { field, selector, value } of updates) {
|
||||
test(`can update ${field}`, async ({ page }) => {
|
||||
await login(page)
|
||||
const username = `playwright-${randomUUID()}`
|
||||
await createUser(page, username)
|
||||
await page.waitForSelector(selector)
|
||||
await page.locator(selector).fill(value)
|
||||
const saveBtn = page.getByRole('button', { name: 'Save' }).last()
|
||||
await expect(saveBtn).toBeEnabled()
|
||||
await saveBtn.click()
|
||||
await expect(page.locator(selector)).toHaveValue(value)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
test('can update username', async ({ page }) => {
|
||||
await login(page)
|
||||
const username = `playwright-${randomUUID()}`
|
||||
await createUser(page, username)
|
||||
await page.waitForSelector('#username')
|
||||
const newUsername = `playwright-${randomUUID()}`
|
||||
await page.locator('#username').fill(newUsername)
|
||||
const saveBtn = page.getByRole('button', { name: 'Save' }).last()
|
||||
await expect(saveBtn).toBeEnabled()
|
||||
await saveBtn.click()
|
||||
await expect(page.locator('#username')).toHaveValue(newUsername)
|
||||
})
|
||||
|
||||
test('can delete a user', async ({ page }) => {
|
||||
await login(page)
|
||||
const username = `playwright-${randomUUID()}`
|
||||
await createUser(page, username)
|
||||
await page.getByRole('button', { name: 'Delete User' }).click()
|
||||
await page.getByRole('dialog').getByRole('button', { name: 'Delete' }).click()
|
||||
await page.waitForURL('**/users')
|
||||
await expect(page.locator(`text=${username}`)).toHaveCount(0)
|
||||
})
|
||||
83
ui/tests/e2e/util.ts
Normal file
83
ui/tests/e2e/util.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { expect } from '@playwright/test'
|
||||
import { test as baseTest } from 'playwright/test'
|
||||
import path from 'path'
|
||||
|
||||
export const test = baseTest.extend({
|
||||
page: async ({ page }, use) => {
|
||||
page.on('console', (msg) => console.log(msg.text()))
|
||||
page.on('response', async (response) => {
|
||||
if (response.status() >= 400) {
|
||||
console.error('Error response:', response.status(), response.url())
|
||||
}
|
||||
expect(response.status()).toBeLessThan(400)
|
||||
})
|
||||
|
||||
await use(page)
|
||||
}
|
||||
})
|
||||
|
||||
export const login = async (page, admin: boolean = true) => {
|
||||
await page.goto('login')
|
||||
if (admin) {
|
||||
await page.getByPlaceholder('Username').fill('admin@catalyst-soar.com')
|
||||
} else {
|
||||
await page.getByPlaceholder('Username').fill('user@catalyst-soar.com')
|
||||
}
|
||||
await page.getByPlaceholder('Password').fill('1234567890')
|
||||
await page.getByRole('button', { name: 'Login' }).click()
|
||||
await page.waitForURL('**/dashboard')
|
||||
}
|
||||
|
||||
export const createTicket = async (page, name: string) => {
|
||||
await page.goto('tickets/incident')
|
||||
await page.getByRole('button', { name: 'New Ticket' }).click()
|
||||
await page.locator('#name').fill(name)
|
||||
await page.locator('#description').fill('Suspicious behavior detected by user in HR department.')
|
||||
await page.locator('#severity').selectOption('Low')
|
||||
await page.getByRole('button', { name: 'Save' }).click()
|
||||
await page.waitForURL('**/tickets/incident/t*')
|
||||
}
|
||||
|
||||
export const createTimeline = async (page, message: string) => {
|
||||
await page.getByRole('tab', { name: 'Timeline' }).click()
|
||||
await page.getByRole('button', { name: 'Add Timeline Item' }).click()
|
||||
await page.getByRole('tabpanel', { name: 'Timeline' }).getByRole('textbox').fill(message)
|
||||
await page.getByRole('button', { name: 'Save' }).click()
|
||||
await expect(page.getByText(message)).toBeVisible()
|
||||
}
|
||||
|
||||
export const createComment = async (page, message: string) => {
|
||||
await page.getByRole('tab', { name: 'Comments' }).click()
|
||||
await page.getByRole('button', { name: 'Add Comment' }).click()
|
||||
await page.getByRole('tabpanel', { name: 'Comments' }).getByRole('textbox').fill(message)
|
||||
await page.getByRole('button', { name: 'Save' }).click()
|
||||
await expect(page.getByText(message)).toBeVisible()
|
||||
}
|
||||
|
||||
export const createTask = async (page, name: string, done: boolean) => {
|
||||
await page.getByRole('tab', { name: 'Tasks' }).click()
|
||||
await page.getByRole('button', { name: 'Add Task' }).click()
|
||||
await page.getByPlaceholder('Add a task...').fill(name)
|
||||
await page.getByRole('button', { name: 'Save' }).click()
|
||||
if (done) {
|
||||
await page.getByRole('checkbox').last().click()
|
||||
}
|
||||
await expect(page.getByText(name)).toBeVisible()
|
||||
}
|
||||
|
||||
export const createLink = async (page, name: string, url: string) => {
|
||||
await page.getByRole('button', { name: 'Add item' }).first().click()
|
||||
await page.locator('input[name="name"]').fill(name)
|
||||
await page.locator('#url').fill(url)
|
||||
await page.getByRole('button', { name: 'Save' }).click()
|
||||
await expect(page.getByText(name)).toBeVisible()
|
||||
}
|
||||
|
||||
export const uploadFile = async (page, filePath: string) => {
|
||||
await page.getByRole('button', { name: 'Add item' }).last().click()
|
||||
await page.setInputFiles('input[type="file"]', filePath)
|
||||
await page.getByRole('button', { name: 'Upload 1 file' }).first().click()
|
||||
await page.getByRole('button', { name: 'Close' }).first().click()
|
||||
const name = path.basename(filePath)
|
||||
await expect(page.getByText(name, { exact: true })).toBeVisible()
|
||||
}
|
||||
Reference in New Issue
Block a user