Extract the operational Model Delivery PWA
This commit is contained in:
commit
958f8d5ff1
46 files changed
+6446
No files matched your search
@@ -0,0 +1,86 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { testAccount } from '../helpers/account';
|
||||
|
||||
test('local recovery settings, masked secret, SSO greeting and offline re-entry', async ({ page, context }) => {
|
||||
const request = context.request;
|
||||
const state = await (await request.get('/api/local-admin/status')).json();
|
||||
if (state.setupRequired) {
|
||||
expect((await request.post('/api/local-admin/setup', { headers: { 'x-model-request': '1' }, data: { ...testAccount, setupToken: 'isolated-test-bootstrap' } })).ok()).toBe(true);
|
||||
await request.post('/api/auth/logout', { headers: { 'x-model-request': '1' } });
|
||||
}
|
||||
await page.goto('/');
|
||||
await expect(page.getByRole('button', { name: 'כניסה עם חשבון המעבדה' })).toBeVisible();
|
||||
await expect(page.locator('a[href="/local-admin"]')).toHaveCount(0);
|
||||
await page.goto('/local-admin');
|
||||
await page.getByLabel('שם משתמש', { exact: true }).fill(testAccount.username);
|
||||
await page.getByLabel('סיסמה', { exact: true }).fill(testAccount.password);
|
||||
await page.getByRole('button', { name: 'כניסה מקומית', exact: true }).click();
|
||||
await expect(page.getByRole('heading', { name: 'Synology SSO Server' })).toBeVisible();
|
||||
await page.getByLabel('כתובת המנפיק (Issuer)', { exact: true }).fill('http://localhost:4005');
|
||||
await page.getByLabel('כתובת גילוי (Well-known URL)').fill('http://localhost:4005/.well-known/openid-configuration');
|
||||
await page.getByLabel('מזהה לקוח (Application ID)', { exact: true }).fill('model-test');
|
||||
await page.getByLabel('סוד לקוח (Application Secret)').fill('mock-test-secret');
|
||||
await page.getByLabel('כתובת חזרה (Redirect URI)').fill('http://localhost:4174/api/auth/callback');
|
||||
await page.getByLabel('הרשאות (Scopes)').fill('openid profile email groups');
|
||||
await page.getByLabel('הגבלת הכניסה לפי קבוצות Synology / AD').check();
|
||||
await page.getByLabel('שם שדה הקבוצות').fill('groups');
|
||||
await page.getByLabel('קבוצות מורשות — קבוצה בכל שורה').fill('model-delivery-users');
|
||||
await page.getByLabel('הפעלת כניסה ארגונית').check();
|
||||
await page.getByLabel('בקשת offline_access לחידוש הכניסה').check();
|
||||
await page.getByRole('button', { name: 'שמירת הגדרות', exact: true }).click();
|
||||
await expect(page.getByRole('status')).toContainText('ההגדרות נשמרו');
|
||||
await expect(page.getByLabel('סוד לקוח (Application Secret)')).toHaveValue('');
|
||||
await page.getByRole('button', { name: 'בדיקת ההגדרות השמורות' }).click();
|
||||
await expect(page.getByRole('status')).toContainText('החיבור לשרת אומת');
|
||||
const directory = page.locator('.directory-settings');
|
||||
await expect(directory.getByRole('heading', { name: 'שמות מתוך Active Directory' })).toBeVisible();
|
||||
await directory.getByLabel('קריאת שמות מהספרייה', { exact: true }).uncheck();
|
||||
await directory.getByLabel('כתובת הספרייה (LDAPS)').fill('ldaps://directory.example.invalid:636');
|
||||
await directory.getByLabel('חשבון קריאה (Bind DN / UPN)').fill('reader@example.invalid');
|
||||
await directory.getByLabel('סיסמת חשבון הקריאה').fill('browser-test-directory-secret');
|
||||
await directory.getByRole('button', { name: 'שמירת הגדרות הספרייה' }).click();
|
||||
await expect(directory.getByRole('status')).toContainText('הגדרות הספרייה נשמרו');
|
||||
await expect(directory.getByLabel('סיסמת חשבון הקריאה')).toHaveValue('');
|
||||
await directory.getByLabel('מזהה SSO לבדיקה').fill('REZNIK\\test.sso');
|
||||
await directory.getByRole('button', { name: 'בדיקת שם מהספרייה' }).click();
|
||||
await expect(directory.getByRole('alert')).toContainText('קריאת השמות כבויה');
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
expect(await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)).toBe(true);
|
||||
await page.screenshot({ path: 'test-results/model-delivery-local-admin.png', fullPage: true });
|
||||
await page.getByRole('link', { name: 'פתיחת האפליקציה' }).click();
|
||||
await expect(page.locator('.greeting')).toHaveText(`שלום, ${testAccount.displayName}`);
|
||||
await page.getByRole('button', { name: 'החשבון שלי' }).click();
|
||||
await page.getByRole('button', { name: 'יציאה מהחשבון' }).click();
|
||||
await page.getByRole('button', { name: 'כניסה עם חשבון המעבדה' }).click();
|
||||
await expect(page.locator('.greeting')).toHaveText('שלום, טום בדיקה');
|
||||
await page.getByRole('button', { name: 'החשבון שלי' }).click();
|
||||
await page.getByLabel('שם לתצוגה', { exact: true }).fill('תום רוף בדיקה');
|
||||
await page.getByRole('button', { name: 'שמירת השם', exact: true }).click();
|
||||
await expect(page.locator('.greeting')).toHaveText('שלום, תום רוף בדיקה');
|
||||
const session = await (await request.get('/api/auth/session')).json();
|
||||
expect(session.user.authProvider).toBe('oidc');
|
||||
expect(session.user.groups).toEqual(['model-delivery-users']);
|
||||
expect(Object.keys(session).sort()).toEqual(['expiresAt', 'user']);
|
||||
expect(await page.evaluate(() => Object.keys(localStorage).some(key => /token|secret/i.test(key)))).toBe(false);
|
||||
await page.evaluate(async () => { await navigator.serviceWorker.ready; });
|
||||
await page.reload();
|
||||
await expect.poll(() => page.evaluate(() => Boolean(navigator.serviceWorker.controller))).toBe(true);
|
||||
await context.setOffline(true);
|
||||
await page.reload();
|
||||
await expect(page.locator('.greeting')).toHaveText('שלום, תום רוף בדיקה');
|
||||
await context.setOffline(false);
|
||||
await page.getByRole('button', { name: 'החשבון שלי' }).click();
|
||||
await page.getByRole('button', { name: 'שימוש בשם הארגוני' }).click();
|
||||
await expect(page.locator('.greeting')).toHaveText('שלום, טום בדיקה');
|
||||
// Restore this reusable test user's preference after checking offline persistence.
|
||||
expect((await request.post('/api/auth/profile', { headers: { 'x-model-request': '1', 'x-model-user': session.user.id }, data: { displayName: 'טום בדיקה' } })).ok()).toBe(true);
|
||||
await page.goto('/local-admin');
|
||||
await expect(page.getByRole('button', { name: 'כניסה מקומית', exact: true })).toBeVisible();
|
||||
await expect(page.getByLabel('סוד לקוח (Application Secret)')).toHaveCount(0);
|
||||
await expect(page.locator('.directory-settings')).toHaveCount(0);
|
||||
// Only the isolated test database is configured by this test. Disable its test provider afterwards.
|
||||
const local = await request.post('/api/local-admin/login', { headers: { 'x-model-request': '1' }, data: { username: testAccount.username, password: testAccount.password } });
|
||||
expect(local.ok()).toBe(true);
|
||||
const { secretConfigured: _, ...settings } = await (await request.get('/api/local-admin/settings')).json();
|
||||
expect((await request.post('/api/local-admin/settings', { headers: { 'x-model-request': '1' }, data: { ...settings, enabled: false } })).ok()).toBe(true);
|
||||
});
|
||||
@@ -0,0 +1,266 @@
|
||||
import { test, expect, type Page } from '@playwright/test';
|
||||
import { testAccount } from '../helpers/account';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
|
||||
test.beforeEach(async ({ context }) => {
|
||||
const request = context.request;
|
||||
const state = await (await request.get('/api/local-admin/status')).json();
|
||||
const result = await request.post(`/api/local-admin/${state.setupRequired ? 'setup' : 'login'}`, { headers: { 'x-model-request': '1' }, data: state.setupRequired ? { ...testAccount, setupToken: 'isolated-test-bootstrap' } : { username: testAccount.username, password: testAccount.password } });
|
||||
expect(result.ok()).toBe(true);
|
||||
});
|
||||
|
||||
async function deliveryForm(page: Page, notes: string) {
|
||||
await page.getByRole('combobox', { name: 'לקוח', exact: true }).selectOption({ label: 'מרפאת הדגמה' });
|
||||
await page.getByRole('combobox', { name: 'כתובת למשלוח', exact: true }).selectOption('20000000-0000-4000-8000-000000000002');
|
||||
await page.getByRole('combobox', { name: 'סוג משלוח', exact: true }).selectOption('10000000-0000-4000-8000-000000000003');
|
||||
await page.getByLabel('מחיר ליחידה (₪)').fill('10.01');
|
||||
await page.getByRole('textbox', { name: /הערות למשלוח/ }).fill(notes);
|
||||
}
|
||||
|
||||
async function openDeliveryView(page: Page) {
|
||||
const heading = page.getByRole('heading', { name: 'המשלוחים שלך' });
|
||||
if (!await heading.isVisible()) await page.getByRole('button', { name: 'משלוחים', exact: true }).click();
|
||||
await expect(heading).toBeVisible();
|
||||
}
|
||||
|
||||
test('online creation then offline save, offline reload, reconnect and server verification', async ({ page, context }) => {
|
||||
const request = context.request;
|
||||
const browserErrors: string[] = [];
|
||||
page.on('pageerror', error => browserErrors.push(error.message));
|
||||
await page.goto('/');
|
||||
await expect(page.getByRole('heading', { name: 'תמונת המצב שלך' })).toBeVisible();
|
||||
await expect(page.locator('.day-card')).toHaveCount(7);
|
||||
await expect(page.getByRole('region', { name: 'פעולות מהירות' }).getByRole('button')).toHaveCount(4);
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
expect(await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)).toBe(true);
|
||||
await expect.poll(() => page.locator('.sidebar').evaluate(element => { const rect = element.getBoundingClientRect(); return rect.left >= innerWidth || rect.right <= 0; })).toBe(true);
|
||||
await page.screenshot({ path: 'test-results/model-delivery-dashboard-mobile.png' });
|
||||
await page.setViewportSize({ width: 1440, height: 900 });
|
||||
await page.getByRole('button', { name: /משלוח חדש/ }).click();
|
||||
await expect(page.getByRole('heading', { name: 'המשלוחים שלך' })).toBeVisible();
|
||||
await expect(page.getByRole('combobox', { name: 'לקוח', exact: true }).locator('option')).toContainText(['בחירת לקוח', 'מרפאת הדגמה']);
|
||||
await expect(page.getByLabel('תאריך מתוכנן')).toHaveValue(/^\d{4}-\d{2}-\d{2}$/);
|
||||
await page.evaluate(async () => { await navigator.serviceWorker.ready; });
|
||||
await page.reload();
|
||||
await openDeliveryView(page);
|
||||
await expect.poll(() => page.evaluate(() => Boolean(navigator.serviceWorker.controller))).toBe(true);
|
||||
|
||||
const onlineNotes = `Online browser test ${Date.now()}`;
|
||||
await deliveryForm(page, onlineNotes);
|
||||
await page.getByRole('radio', { name: /שעה אחרת/ }).check();
|
||||
await page.getByLabel('שעה מדויקת', { exact: true }).fill('14:35');
|
||||
await page.getByRole('button', { name: '+ שמירת משלוח', exact: true }).click();
|
||||
await expect(page.locator('.detail-panel')).toContainText(onlineNotes);
|
||||
await expect(page.locator('.detail-panel')).toContainText('שעה אחרת · 14:35');
|
||||
await expect(page.locator('.delivery-row[aria-pressed="true"]')).toContainText('מסונכרן');
|
||||
await expect(page.locator('.delivery-row[aria-pressed="true"]')).toContainText('#');
|
||||
|
||||
await context.setOffline(true);
|
||||
await expect(page.locator('.connection')).toContainText('ללא חיבור לרשת');
|
||||
const offlineNotes = `Offline browser test ${Date.now()}`;
|
||||
await deliveryForm(page, offlineNotes);
|
||||
await page.getByRole('radio', { name: /צהריים/ }).check();
|
||||
await page.getByRole('button', { name: '+ שמירת משלוח', exact: true }).click();
|
||||
await expect(page.locator('.detail-panel')).toContainText(offlineNotes);
|
||||
const offlineRow = page.locator('.delivery-row[aria-pressed="true"]');
|
||||
await expect(offlineRow).toContainText('ממתין לסנכרון');
|
||||
await expect(offlineRow).toContainText('ממתין למספר');
|
||||
const rowId = await offlineRow.getAttribute('data-testid');
|
||||
expect(rowId).toBeTruthy();
|
||||
await page.reload();
|
||||
await openDeliveryView(page);
|
||||
await expect(page.getByTestId(rowId!)).toContainText('ממתין לסנכרון');
|
||||
await expect(page.getByTestId(rowId!)).toContainText('ממתין למספר');
|
||||
|
||||
await context.setOffline(false);
|
||||
try { await expect(page.getByTestId(rowId!)).toContainText('מסונכרן'); }
|
||||
catch (error) {
|
||||
console.log(await page.evaluate(async () => ({ online: navigator.onLine, connection: document.querySelector('.connection')?.textContent, sync: document.querySelector('.sync-button')?.textContent, alerts: Array.from(document.querySelectorAll('.alert')).map(e => e.textContent), locks: await navigator.locks.query() })));
|
||||
throw error;
|
||||
}
|
||||
await expect(page.getByTestId(rowId!)).toContainText('#');
|
||||
await page.reload();
|
||||
await openDeliveryView(page);
|
||||
await expect(page.getByTestId(rowId!)).toContainText('מסונכרן');
|
||||
const allChanges: Array<{ change: { entityType: string; record: { id: string; notes?: string; deliveryNumber?: number; deliverySlot?: string; specificTime?: string | null } } }> = [];
|
||||
let cursor = '0';
|
||||
const session = await (await request.get('/api/auth/session')).json();
|
||||
while (true) {
|
||||
const response = await request.get(`/api/sync/pull?cursor=${cursor}&limit=200`, { headers: { 'x-model-user': session.user.id } });
|
||||
expect(response.ok()).toBe(true);
|
||||
const result = await response.json(); allChanges.push(...result.changes); cursor = result.nextCursor;
|
||||
if (!result.hasMore) break;
|
||||
}
|
||||
const saved = allChanges.filter(c => c.change.entityType === 'delivery' && c.change.record.notes === offlineNotes);
|
||||
expect(saved).toHaveLength(1);
|
||||
expect(`delivery-${saved[0]!.change.record.id}`).toBe(rowId);
|
||||
expect(saved[0]!.change.record.deliveryNumber).toBeGreaterThan(0);
|
||||
expect(saved[0]!.change.record.deliverySlot).toBe('afternoon');
|
||||
const onlineSaved = allChanges.filter(c => c.change.record.notes === onlineNotes);
|
||||
expect(onlineSaved).toHaveLength(1);
|
||||
expect(onlineSaved[0]!.change.record).toMatchObject({ deliverySlot: 'custom', specificTime: '14:35' });
|
||||
|
||||
for (const viewport of [{ width: 390, height: 844 }, { width: 768, height: 1024 }, { width: 1024, height: 768 }, { width: 1440, height: 900 }]) {
|
||||
await page.setViewportSize(viewport);
|
||||
await expect(page.getByRole('button', { name: '+ שמירת משלוח' })).toBeVisible();
|
||||
expect(await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)).toBe(true);
|
||||
}
|
||||
await page.screenshot({ path: 'test-results/model-delivery-desktop.png', fullPage: true });
|
||||
await page.getByRole('button', { name: 'לוח בקרה', exact: true }).click();
|
||||
await expect(page.getByRole('region', { name: 'לוח משלוחים שבועי' })).toBeVisible();
|
||||
await page.screenshot({ path: 'test-results/model-delivery-dashboard.png' });
|
||||
await page.getByRole('button', { name: 'עלויות', exact: true }).click();
|
||||
await expect(page.getByRole('heading', { name: 'עלויות משלוחים' })).toBeVisible();
|
||||
await page.screenshot({ path: 'test-results/model-delivery-costs.png' });
|
||||
await openDeliveryView(page);
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
await expect(page.getByRole('button', { name: 'פתיחת תפריט' })).toBeVisible();
|
||||
await page.getByRole('button', { name: 'פתיחת תפריט' }).click();
|
||||
await expect(page.locator('.sidebar')).toHaveClass(/open/);
|
||||
await page.getByRole('button', { name: 'משלוחים', exact: true }).click();
|
||||
await expect(page.locator('.sidebar')).not.toHaveClass(/open/);
|
||||
await page.screenshot({ path: 'test-results/model-delivery-mobile.png', fullPage: true });
|
||||
expect(browserErrors).toEqual([]);
|
||||
});
|
||||
|
||||
test('creates an offline customer and assigned address before its delivery, then syncs in order', async ({ page, context }) => {
|
||||
await page.goto('/');
|
||||
await openDeliveryView(page);
|
||||
await expect(page.getByRole('combobox', { name: 'סוג משלוח', exact: true }).locator('option')).toHaveCount(3);
|
||||
await context.setOffline(true);
|
||||
await expect(page.locator('.connection')).toContainText('ללא חיבור לרשת');
|
||||
await page.getByRole('button', { name: 'לקוחות', exact: true }).click();
|
||||
const name = `לקוח בדיקה ${Date.now()}`;
|
||||
await page.getByRole('button', { name: 'לקוח חדש', exact: true }).first().click();
|
||||
await page.getByLabel('שם הלקוח').fill(name);
|
||||
await page.getByLabel('איש קשר').fill('איש קשר לבדיקה');
|
||||
await page.getByLabel('מספר טלפון').fill('050-1234567');
|
||||
await page.getByLabel('בוקר', { exact: true }).check();
|
||||
await page.getByRole('button', { name: 'יצירת לקוח', exact: true }).click();
|
||||
await expect(page.getByRole('heading', { name, exact: true })).toBeVisible();
|
||||
await page.getByLabel('שם הכתובת').fill('ראשית');
|
||||
await page.getByLabel('עיר', { exact: true }).fill('תל אביב');
|
||||
await page.getByLabel('רחוב', { exact: true }).fill('הבדיקה');
|
||||
await page.getByLabel('מספר', { exact: true }).fill('7');
|
||||
await page.getByRole('button', { name: 'הוספת כתובת', exact: true }).click();
|
||||
await expect(page.getByText('הבדיקה 7, תל אביב', { exact: true })).toBeVisible();
|
||||
await page.getByRole('button', { name: 'משלוחים', exact: true }).click();
|
||||
await page.getByRole('combobox', { name: 'לקוח', exact: true }).selectOption({ label: name });
|
||||
await page.getByRole('combobox', { name: 'כתובת למשלוח', exact: true }).selectOption({ index: 1 });
|
||||
await page.getByRole('button', { name: '+ שמירת משלוח', exact: true }).click();
|
||||
const row = page.locator('.delivery-row').filter({ hasText: name });
|
||||
await expect(row).toContainText('ממתין לסנכרון');
|
||||
await context.setOffline(false);
|
||||
await expect(row).toContainText('מסונכרן');
|
||||
await expect(row).toContainText('#');
|
||||
await expect(page.getByRole('alert')).toHaveCount(0);
|
||||
});
|
||||
|
||||
test('edits and archives a customer while preserving related deliveries', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.getByRole('button', { name: 'לקוחות', exact: true }).click();
|
||||
await page.getByRole('button', { name: 'לקוח חדש', exact: true }).first().click();
|
||||
const name = `מרפאת פרופיל ${Date.now()}`;
|
||||
await page.getByLabel('שם הלקוח').fill(name);
|
||||
await page.getByLabel('איש קשר').fill('נועה כהן');
|
||||
await page.getByLabel('מספר טלפון').fill('052-7654321');
|
||||
await page.getByLabel('בוקר', { exact: true }).check();
|
||||
await page.getByLabel('תחילת בוקר').fill('08:15');
|
||||
await page.getByLabel('סיום בוקר').fill('11:45');
|
||||
await page.getByLabel('הערות ללקוח').fill('כניסה מהחניון');
|
||||
await page.getByRole('button', { name: 'יצירת לקוח' }).click();
|
||||
await expect(page.getByRole('heading', { name, exact: true })).toBeVisible();
|
||||
const clientRow = page.locator('.client-row').filter({ hasText: name });
|
||||
await expect(clientRow.locator('.sync-dot')).toHaveClass(/synced/);
|
||||
await page.getByLabel('שם הכתובת').fill('מרפאה');
|
||||
await page.getByLabel('עיר', { exact: true }).fill('חיפה');
|
||||
await page.getByLabel('רחוב', { exact: true }).fill('הנמל');
|
||||
await page.getByLabel('מספר', { exact: true }).fill('12');
|
||||
await page.getByRole('button', { name: 'הוספת כתובת' }).click();
|
||||
await expect(page.locator('.associated-row').filter({ hasText: 'הנמל 12, חיפה' }).last().locator('.sync-dot')).toHaveClass(/synced/);
|
||||
await page.getByRole('button', { name: 'משלוחים', exact: true }).click();
|
||||
await page.getByRole('combobox', { name: 'לקוח', exact: true }).selectOption({ label: name });
|
||||
await page.getByRole('combobox', { name: 'כתובת למשלוח', exact: true }).selectOption({ index: 1 });
|
||||
await page.getByRole('button', { name: '+ שמירת משלוח' }).click();
|
||||
await expect(page.locator('.delivery-row').filter({ hasText: name })).toContainText('מסונכרן');
|
||||
await page.getByRole('button', { name: 'לקוחות', exact: true }).click();
|
||||
await clientRow.click();
|
||||
await expect(page.getByText(/משלוח #/)).toBeVisible();
|
||||
await expect(page.getByText('הנמל 12, חיפה', { exact: true })).toBeVisible();
|
||||
await page.screenshot({ path: 'test-results/model-delivery-clients.png' });
|
||||
await page.getByRole('button', { name: 'עריכה', exact: true }).click();
|
||||
await page.getByLabel('איש קשר').fill('נועה לוי');
|
||||
await page.getByRole('button', { name: 'שמירת שינויים' }).click();
|
||||
await expect(page.locator('.client-summary strong').filter({ hasText: 'נועה לוי' })).toBeVisible();
|
||||
await expect(clientRow.locator('.sync-dot')).toHaveClass(/synced/);
|
||||
await page.getByRole('button', { name: 'הסרה', exact: true }).click();
|
||||
await expect(page.getByRole('alert')).toContainText('יישמרו ויישארו משויכים');
|
||||
await page.getByRole('button', { name: 'העברה לארכיון' }).click();
|
||||
await page.getByLabel('הצגת ארכיון').check();
|
||||
await expect(clientRow).toBeVisible();
|
||||
await clientRow.click();
|
||||
await expect(page.getByText(/משלוח #/)).toBeVisible();
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
expect(await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)).toBe(true);
|
||||
await expect(page.locator('.sidebar')).not.toHaveClass(/open/);
|
||||
await expect.poll(() => page.locator('.sidebar').evaluate(element => { const rect = element.getBoundingClientRect(); return rect.left >= innerWidth || rect.right <= 0; })).toBe(true);
|
||||
await page.screenshot({ path: 'test-results/model-delivery-clients-mobile.png' });
|
||||
await page.getByRole('button', { name: 'פתיחת תפריט' }).click();
|
||||
await expect(page.locator('.sidebar')).toHaveClass(/open/);
|
||||
await page.getByRole('button', { name: 'משלוחים', exact: true }).click();
|
||||
await expect(page.getByRole('combobox', { name: 'לקוח', exact: true }).locator('option', { hasText: name })).toHaveCount(0);
|
||||
});
|
||||
|
||||
test('keeps an offline edit across reload, resolves a concurrent edit explicitly, then cancels', async ({ page, context }) => {
|
||||
const request = context.request;
|
||||
await page.goto('/');
|
||||
await openDeliveryView(page);
|
||||
await expect(page.getByRole('combobox', { name: 'סוג משלוח', exact: true }).locator('option')).toHaveCount(3);
|
||||
await page.evaluate(async () => { await navigator.serviceWorker.ready; });
|
||||
await page.reload();
|
||||
await openDeliveryView(page);
|
||||
const conflictNotes = `Conflict browser test ${Date.now()}`;
|
||||
await deliveryForm(page, conflictNotes);
|
||||
await page.getByRole('button', { name: '+ שמירת משלוח', exact: true }).click();
|
||||
await expect(page.locator('.detail-panel')).toContainText(conflictNotes);
|
||||
const row = page.locator('.delivery-row[aria-pressed="true"]');
|
||||
await expect(row).toContainText('מסונכרן');
|
||||
const rowId = (await row.getAttribute('data-testid'))!;
|
||||
const number = await row.locator('.row-top strong').innerText();
|
||||
await context.setOffline(true);
|
||||
await page.getByRole('button', { name: 'עריכת משלוח', exact: true }).click();
|
||||
await page.getByLabel('הערות מעודכנות').fill('Offline edit to keep');
|
||||
await page.getByRole('button', { name: 'שמירת שינויים', exact: true }).click();
|
||||
await expect(page.getByTestId(rowId)).toContainText('ממתין לסנכרון');
|
||||
await page.reload();
|
||||
await openDeliveryView(page);
|
||||
await page.getByTestId(rowId).click();
|
||||
await expect(page.locator('.detail-panel')).toContainText('Offline edit to keep');
|
||||
const session = await (await request.get('/api/auth/session')).json();
|
||||
const headers = { 'x-model-request': '1', 'x-model-user': session.user.id };
|
||||
const remote = await request.post('/api/sync/push', { headers, data: { operationId: randomUUID(), deviceId: randomUUID(), entityId: rowId.replace('delivery-', ''), baseVersion: 1, kind: 'delivery.update', data: { customerId: '20000000-0000-4000-8000-000000000001', addressId: '20000000-0000-4000-8000-000000000002', notes: 'Other device edit' } } });
|
||||
expect(remote.ok()).toBe(true);
|
||||
await context.setOffline(false);
|
||||
const panel = page.getByRole('region', { name: 'פתרון התנגשות' });
|
||||
await expect(panel).toBeVisible();
|
||||
await expect(panel).toContainText('Offline edit to keep');
|
||||
await expect(panel).toContainText('Other device edit');
|
||||
await page.getByRole('button', { name: 'החלת השינוי שלי על הגרסה החדשה' }).click();
|
||||
await expect(page.getByTestId(rowId)).toContainText('מסונכרן');
|
||||
await expect(panel).toHaveCount(0);
|
||||
await expect(page.locator('.detail-panel')).toContainText('Offline edit to keep');
|
||||
await context.setOffline(true);
|
||||
await page.getByRole('button', { name: 'ביטול משלוח', exact: true }).click();
|
||||
await page.getByLabel('סיבת הביטול').fill('Cancelled in browser test');
|
||||
await page.getByRole('button', { name: 'אישור ביטול משלוח', exact: true }).click();
|
||||
await expect(page.getByTestId(rowId)).toContainText('מבוטל');
|
||||
await page.reload();
|
||||
await openDeliveryView(page);
|
||||
await page.getByTestId(rowId).click();
|
||||
await expect(page.getByTestId(rowId)).toContainText('ממתין לסנכרון');
|
||||
await context.setOffline(false);
|
||||
await expect(page.getByTestId(rowId)).toContainText('מסונכרן');
|
||||
await expect(page.getByTestId(rowId)).toContainText(number);
|
||||
await expect(page.getByRole('button', { name: 'עריכת משלוח', exact: true })).toBeDisabled();
|
||||
await expect(page.locator('.detail-panel')).toContainText('15.02');
|
||||
});
|
||||
Reference in new issue
Block a user