fix tests, add autofocus disable option for dropdown

This commit is contained in:
Gregor Vostrak
2025-04-15 15:18:02 +02:00
parent d03dd60864
commit 15ac3e9a43
13 changed files with 37 additions and 32 deletions

View File

@@ -109,7 +109,7 @@ services:
- sail - sail
- reverse-proxy - reverse-proxy
playwright: playwright:
image: mcr.microsoft.com/playwright:v1.50.0-jammy image: mcr.microsoft.com/playwright:v1.51.1-jammy
command: ['npx', 'playwright', 'test', '--ui-port=8080', '--ui-host=0.0.0.0'] command: ['npx', 'playwright', 'test', '--ui-port=8080', '--ui-host=0.0.0.0']
working_dir: /src working_dir: /src
extra_hosts: extra_hosts:

View File

@@ -36,7 +36,7 @@ test('can register and delete account', async ({ page }) => {
await page.goto(PLAYWRIGHT_BASE_URL + '/user/profile'); await page.goto(PLAYWRIGHT_BASE_URL + '/user/profile');
await page.getByRole('button', { name: 'Delete Account' }).click(); await page.getByRole('button', { name: 'Delete Account' }).click();
await page.getByPlaceholder('Password').fill(password); await page.getByPlaceholder('Password').fill(password);
await page.getByRole('button', { name: 'Delete Account' }).nth(1).click(); await page.getByRole('button', { name: 'Delete Account' }).click();
await page.waitForURL(PLAYWRIGHT_BASE_URL + '/login'); await page.waitForURL(PLAYWRIGHT_BASE_URL + '/login');
await page.goto(PLAYWRIGHT_BASE_URL + '/login'); await page.goto(PLAYWRIGHT_BASE_URL + '/login');
await page.getByLabel('Email').fill(email); await page.getByLabel('Email').fill(email);

View File

@@ -16,7 +16,7 @@ test('test that creating and deleting a new client via the modal works', async (
await page.getByRole('button', { name: 'Create Client' }).click(); await page.getByRole('button', { name: 'Create Client' }).click();
await page.getByPlaceholder('Client Name').fill(newClientName); await page.getByPlaceholder('Client Name').fill(newClientName);
await Promise.all([ await Promise.all([
page.getByRole('button', { name: 'Create Client' }).nth(1).click(), page.getByRole('button', { name: 'Create Client' }).click(),
page.waitForResponse( page.waitForResponse(
async (response) => async (response) =>
response.url().includes('/clients') && response.url().includes('/clients') &&
@@ -56,12 +56,12 @@ test('test that archiving and unarchiving clients works', async ({ page }) => {
await page.getByRole('button', { name: 'Create Client' }).click(); await page.getByRole('button', { name: 'Create Client' }).click();
await page.getByLabel('Client Name').fill(newClientName); await page.getByLabel('Client Name').fill(newClientName);
await page.getByRole('button', { name: 'Create Client' }).nth(1).click(); await page.getByRole('button', { name: 'Create Client' }).click();
await expect(page.getByText(newClientName)).toBeVisible(); await expect(page.getByText(newClientName)).toBeVisible();
await page.getByRole('row').first().getByRole('button').click(); await page.getByRole('row').first().getByRole('button').click();
await Promise.all([ await Promise.all([
page.getByRole('button').getByText('Archive').first().click(), page.getByRole('menuitem').getByText('Archive').click(),
expect(page.getByText(newClientName)).not.toBeVisible(), expect(page.getByText(newClientName)).not.toBeVisible(),
]); ]);
await Promise.all([ await Promise.all([
@@ -71,7 +71,7 @@ test('test that archiving and unarchiving clients works', async ({ page }) => {
await page.getByRole('row').first().getByRole('button').click(); await page.getByRole('row').first().getByRole('button').click();
await Promise.all([ await Promise.all([
page.getByRole('button').getByText('Unarchive').first().click(), page.getByRole('menuitem').getByText('Unarchive').click(),
expect(page.getByText(newClientName)).not.toBeVisible(), expect(page.getByText(newClientName)).not.toBeVisible(),
]); ]);
await Promise.all([ await Promise.all([

View File

@@ -82,7 +82,7 @@ test('test that organization billable rate can be updated with all existing time
await goToMembersPage(page); await goToMembersPage(page);
const newBillableRate = Math.round(Math.random() * 10000); const newBillableRate = Math.round(Math.random() * 10000);
await page.getByRole('row').first().getByRole('button').click(); await page.getByRole('row').first().getByRole('button').click();
await page.getByRole('button').getByText('Edit').first().click(); await page.getByRole('menuitem').getByText('Edit').click();
await page.getByText('Organization Default Rate').click(); await page.getByText('Organization Default Rate').click();
await page.getByText('Custom Rate').click(); await page.getByText('Custom Rate').click();
await page await page

View File

@@ -17,7 +17,7 @@ test('test that updating project member billable rate works for existing time en
await page.getByRole('button', { name: 'Create Project' }).click(); await page.getByRole('button', { name: 'Create Project' }).click();
await page.getByLabel('Project Name').fill(newProjectName); await page.getByLabel('Project Name').fill(newProjectName);
await page.getByRole('button', { name: 'Create Project' }).nth(1).click(); await page.getByRole('button', { name: 'Create Project' }).click();
await expect(page.getByText(newProjectName)).toBeVisible(); await expect(page.getByText(newProjectName)).toBeVisible();
await page.getByText(newProjectName).click(); await page.getByText(newProjectName).click();
@@ -35,8 +35,7 @@ test('test that updating project member billable rate works for existing time en
.getByRole('button') .getByRole('button')
.click(); .click();
await page await page
.getByRole('button', { name: 'Edit Project Member' }) .getByRole('menuitem', { name: 'Edit Project Member' })
.first()
.click(); .click();
await page.getByLabel('Billable Rate').fill(newBillableRate.toString()); await page.getByLabel('Billable Rate').fill(newBillableRate.toString());
await page.getByRole('button', { name: 'Update Project Member' }).click(); await page.getByRole('button', { name: 'Update Project Member' }).click();

View File

@@ -17,7 +17,7 @@ test('test that creating and deleting a new project via the modal works', async
await page.getByRole('button', { name: 'Create Project' }).click(); await page.getByRole('button', { name: 'Create Project' }).click();
await page.getByLabel('Project Name').fill(newProjectName); await page.getByLabel('Project Name').fill(newProjectName);
await Promise.all([ await Promise.all([
page.getByRole('button', { name: 'Create Project' }).nth(1).click(), page.getByRole('button', { name: 'Create Project' }).click(),
page.waitForResponse( page.waitForResponse(
async (response) => async (response) =>
response.url().includes('/projects') && response.url().includes('/projects') &&
@@ -62,12 +62,12 @@ test('test that archiving and unarchiving projects works', async ({ page }) => {
await page.getByRole('button', { name: 'Create Project' }).click(); await page.getByRole('button', { name: 'Create Project' }).click();
await page.getByLabel('Project Name').fill(newProjectName); await page.getByLabel('Project Name').fill(newProjectName);
await page.getByRole('button', { name: 'Create Project' }).nth(1).click(); await page.getByRole('button', { name: 'Create Project' }).click();
await expect(page.getByText(newProjectName)).toBeVisible(); await expect(page.getByText(newProjectName)).toBeVisible();
await page.getByRole('row').first().getByRole('button').click(); await page.getByRole('row').first().getByRole('button').click();
await Promise.all([ await Promise.all([
page.getByRole('button').getByText('Archive').first().click(), page.getByRole('menuitem').getByText('Archive').first().click(),
expect(page.getByText(newProjectName)).not.toBeVisible(), expect(page.getByText(newProjectName)).not.toBeVisible(),
]); ]);
await Promise.all([ await Promise.all([
@@ -77,7 +77,7 @@ test('test that archiving and unarchiving projects works', async ({ page }) => {
await page.getByRole('row').first().getByRole('button').click(); await page.getByRole('row').first().getByRole('button').click();
await Promise.all([ await Promise.all([
page.getByRole('button').getByText('Unarchive').first().click(), page.getByRole('menuitem').getByText('Unarchive').first().click(),
expect(page.getByText(newProjectName)).not.toBeVisible(), expect(page.getByText(newProjectName)).not.toBeVisible(),
]); ]);
await Promise.all([ await Promise.all([
@@ -96,11 +96,11 @@ test('test that updating billable rate works with existing time entries', async
await page.getByRole('button', { name: 'Create Project' }).click(); await page.getByRole('button', { name: 'Create Project' }).click();
await page.getByLabel('Project Name').fill(newProjectName); await page.getByLabel('Project Name').fill(newProjectName);
await page.getByRole('button', { name: 'Create Project' }).nth(1).click(); await page.getByRole('button', { name: 'Create Project' }).click();
await expect(page.getByText(newProjectName)).toBeVisible(); await expect(page.getByText(newProjectName)).toBeVisible();
await page.getByRole('row').first().getByRole('button').click(); await page.getByRole('row').first().getByRole('button').click();
await page.getByRole('button').getByText('Edit').first().click(), await page.getByRole('menuitem').getByText('Edit').first().click();
await page.getByText('Non-Billable').click(); await page.getByText('Non-Billable').click();
await page.getByText('Custom Rate').click(); await page.getByText('Custom Rate').click();
await page await page

View File

@@ -15,7 +15,7 @@ test('test that creating and deleting a new client via the modal works', async (
await page.getByRole('button', { name: 'Create Tag' }).click(); await page.getByRole('button', { name: 'Create Tag' }).click();
await page.getByPlaceholder('Tag Name').fill(newTagName); await page.getByPlaceholder('Tag Name').fill(newTagName);
await Promise.all([ await Promise.all([
page.getByRole('button', { name: 'Create Tag' }).nth(1).click(), page.getByRole('button', { name: 'Create Tag' }).click(),
page.waitForResponse( page.waitForResponse(
async (response) => async (response) =>
response.url().includes('/tags') && response.url().includes('/tags') &&

View File

@@ -16,7 +16,7 @@ test('test that creating and deleting a new tag in a new project works', async (
await page.getByRole('button', { name: 'Create Project' }).click(); await page.getByRole('button', { name: 'Create Project' }).click();
await page.getByLabel('Project Name').fill(newProjectName); await page.getByLabel('Project Name').fill(newProjectName);
await Promise.all([ await Promise.all([
page.getByRole('button', { name: 'Create Project' }).nth(1).click(), page.getByRole('button', { name: 'Create Project' }).click(),
page.waitForResponse( page.waitForResponse(
async (response) => async (response) =>
response.url().includes('/projects') && response.url().includes('/projects') &&
@@ -41,7 +41,7 @@ test('test that creating and deleting a new tag in a new project works', async (
await page.getByPlaceholder('Task Name').fill(newTaskName); await page.getByPlaceholder('Task Name').fill(newTaskName);
await Promise.all([ await Promise.all([
page.getByRole('button', { name: 'Create Task' }).nth(1).click(), page.getByRole('button', { name: 'Create Task' }).click(),
page.waitForResponse( page.waitForResponse(
async (response) => async (response) =>
response.url().includes('/tasks') && response.url().includes('/tasks') &&
@@ -107,20 +107,20 @@ test('test that archiving and unarchiving tasks works', async ({ page }) => {
await page.getByRole('button', { name: 'Create Project' }).click(); await page.getByRole('button', { name: 'Create Project' }).click();
await page.getByLabel('Project Name').fill(newProjectName); await page.getByLabel('Project Name').fill(newProjectName);
await page.getByRole('button', { name: 'Create Project' }).nth(1).click(); await page.getByRole('button', { name: 'Create Project' }).click();
await expect(page.getByText(newProjectName)).toBeVisible(); await expect(page.getByText(newProjectName)).toBeVisible();
await page.getByText(newProjectName).click(); await page.getByText(newProjectName).click();
await page.getByRole('button', { name: 'Create Task' }).click(); await page.getByRole('button', { name: 'Create Task' }).click();
await page.getByPlaceholder('Task Name').fill(newTaskName); await page.getByPlaceholder('Task Name').fill(newTaskName);
await page.getByRole('button', { name: 'Create Task' }).nth(1).click(); await page.getByRole('button', { name: 'Create Task' }).click();
await expect(page.getByRole('table')).toContainText(newTaskName); await expect(page.getByRole('table')).toContainText(newTaskName);
await page.getByRole('row').first().getByRole('button').click(); await page.getByRole('row').first().getByRole('button').click();
await Promise.all([ await Promise.all([
page.getByRole('button').getByText('Mark as done').first().click(), page.getByRole('menuitem').getByText('Mark as done').first().click(),
expect(page.getByText(newTaskName)).not.toBeVisible(), expect(page.getByText(newTaskName)).not.toBeVisible(),
]); ]);
await Promise.all([ await Promise.all([
@@ -130,7 +130,7 @@ test('test that archiving and unarchiving tasks works', async ({ page }) => {
await page.getByRole('row').first().getByRole('button').click(); await page.getByRole('row').first().getByRole('button').click();
await Promise.all([ await Promise.all([
page.getByRole('button').getByText('Mark as active').first().click(), page.getByRole('menuitem').getByText('Mark as active').first().click(),
expect(page.getByText(newTaskName)).not.toBeVisible(), expect(page.getByText(newTaskName)).not.toBeVisible(),
]); ]);
await Promise.all([ await Promise.all([

View File

@@ -2,11 +2,11 @@
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
:root.dark { :root.dark {
--color-bg-primary: #0f1011; --color-bg-primary: #101012;
--color-bg-secondary: #17181a; --color-bg-secondary: #17181B;
--color-bg-tertiary: #2A2C32; --color-bg-tertiary: #2A2C32;
--color-bg-quaternary: #141518; --color-bg-quaternary: #141518;
--color-bg-background: #0B0B0B; --color-bg-background: #090909;
--color-text-primary: #ffffff; --color-text-primary: #ffffff;
--color-text-secondary: #e3e4e6; --color-text-secondary: #e3e4e6;
--color-text-tertiary: #969799; --color-text-tertiary: #969799;
@@ -22,7 +22,7 @@
--theme-color-menu-active: var(--color-bg-secondary); --theme-color-menu-active: var(--color-bg-secondary);
--theme-color-card-background: var(--color-bg-secondary); --theme-color-card-background: var(--color-bg-secondary);
--theme-shadow-card: 0 4px 7px 0px rgb(0 0 0 / 30%); --theme-shadow-card: 0 4px 7px 0px rgb(0 0 0 / 15%);
--theme-shadow-dropdown: 0 4px 7px 0px rgb(0 0 0 / 40%); --theme-shadow-dropdown: 0 4px 7px 0px rgb(0 0 0 / 40%);
--theme-color-card-background-active: var(--color-bg-tertiary); --theme-color-card-background-active: var(--color-bg-tertiary);

View File

@@ -266,7 +266,7 @@ const page = usePage<{
<BillingBanner v-if="isBillingActivated()" /> <BillingBanner v-if="isBillingActivated()" />
<div <div
class="min-h-screen bg-default-background border-l border-default-background-separator"> class="min-h-screen flex flex-col bg-default-background border-l border-default-background-separator">
<!-- Page Heading --> <!-- Page Heading -->
<header <header
v-if="$slots.header" v-if="$slots.header"
@@ -281,7 +281,7 @@ const page = usePage<{
</header> </header>
<!-- Page Content --> <!-- Page Content -->
<main class="pb-28"> <main class="pb-28 flex-1">
<slot /> <slot />
</main> </main>

View File

@@ -10,7 +10,6 @@ withDefaults(
} }
); );
</script> </script>
Modal.vue
<template> <template>
<button <button
:type="type" :type="type"

View File

@@ -5,18 +5,23 @@ const props = withDefaults(
defineProps<{ defineProps<{
align?: 'center' | 'end' | 'start'; align?: 'center' | 'end' | 'start';
closeOnContentClick?: boolean; closeOnContentClick?: boolean;
autoFocus?: boolean;
}>(), }>(),
{ {
align: 'start', align: 'start',
closeOnContentClick: true, closeOnContentClick: true,
autoFocus: true,
} }
); );
const emit = defineEmits(['open', 'submit']); const emit = defineEmits(['open', 'submit']);
const open = defineModel({ default: false }); const open = defineModel({ default: false });
function handleAutofocus(event: Event) {
if (props.autoFocus === false) {
event.preventDefault();
}
}
function onContentClick() { function onContentClick() {
if (props.closeOnContentClick === true) { if (props.closeOnContentClick === true) {
@@ -42,6 +47,7 @@ function onOpenChange(value: boolean) {
<PopoverContent <PopoverContent
:align="align" :align="align"
class="rounded-lg overflow-hidden relative border border-card-border overflow-none shadow-dropdown bg-card-background" class="rounded-lg overflow-hidden relative border border-card-border overflow-none shadow-dropdown bg-card-background"
@open-auto-focus="handleAutofocus"
@click="onContentClick"> @click="onContentClick">
<slot name="content" /> <slot name="content" />
</PopoverContent> </PopoverContent>

View File

@@ -171,6 +171,7 @@ function closeAndFocusInput() {
<Dropdown <Dropdown
v-model="open" v-model="open"
align="center" align="center"
:auto-focus="false"
:close-on-content-click="false" :close-on-content-click="false"
@submit="open = false"> @submit="open = false">
<template #trigger> <template #trigger>