test: fix broken suites
This commit is contained in:
@@ -136,6 +136,7 @@ vi.mock('@/lib/plugin-hooks', () => ({
|
|||||||
getRecipientSuggestions: { call: async () => [] },
|
getRecipientSuggestions: { call: async () => [] },
|
||||||
onSend: { call: async () => [] },
|
onSend: { call: async () => [] },
|
||||||
beforeSend: { call: async () => [] },
|
beforeSend: { call: async () => [] },
|
||||||
|
onRecipientChipsChange: { transform: async (chips: unknown) => chips },
|
||||||
},
|
},
|
||||||
contactHooks: {
|
contactHooks: {
|
||||||
search: { call: async () => [] },
|
search: { call: async () => [] },
|
||||||
@@ -229,8 +230,10 @@ describe('RecipientChipInput drag and drop', () => {
|
|||||||
const dt = new MockDataTransfer();
|
const dt = new MockDataTransfer();
|
||||||
fireEvent.dragStart(chipSpan, { dataTransfer: dt });
|
fireEvent.dragStart(chipSpan, { dataTransfer: dt });
|
||||||
|
|
||||||
|
// The enrichment pass may have stamped extra display metadata on the
|
||||||
|
// chip by drag time, so match the essential fields rather than deep-equal.
|
||||||
const payload = JSON.parse(dt.getData('application/x-recipient-chip'));
|
const payload = JSON.parse(dt.getData('application/x-recipient-chip'));
|
||||||
expect(payload).toEqual({ recipient: { email: 'alice@example.com' }, fromField: 'to', fromIndex: 0 });
|
expect(payload).toMatchObject({ recipient: { email: 'alice@example.com' }, fromField: 'to', fromIndex: 0 });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('keeps a display name with a comma in a single chip (array model)', async () => {
|
it('keeps a display name with a comma in a single chip (array model)', async () => {
|
||||||
@@ -244,7 +247,7 @@ describe('RecipientChipInput drag and drop', () => {
|
|||||||
const dt = new MockDataTransfer();
|
const dt = new MockDataTransfer();
|
||||||
fireEvent.dragStart(chipSpan, { dataTransfer: dt });
|
fireEvent.dragStart(chipSpan, { dataTransfer: dt });
|
||||||
const payload = JSON.parse(dt.getData('application/x-recipient-chip'));
|
const payload = JSON.parse(dt.getData('application/x-recipient-chip'));
|
||||||
expect(payload).toEqual({ recipient: { name: 'Doo, John', email: 'john@doo.org' }, fromField: 'to', fromIndex: 0 });
|
expect(payload).toMatchObject({ recipient: { name: 'Doo, John', email: 'john@doo.org' }, fromField: 'to', fromIndex: 0 });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('onDragEnd clears the opacity class on the chip', async () => {
|
it('onDragEnd clears the opacity class on the chip', async () => {
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ vi.mock('@/lib/plugin-hooks', () => ({
|
|||||||
getRecipientSuggestions: { call: async () => [] },
|
getRecipientSuggestions: { call: async () => [] },
|
||||||
onSend: { call: async () => [] },
|
onSend: { call: async () => [] },
|
||||||
beforeSend: { call: async () => [] },
|
beforeSend: { call: async () => [] },
|
||||||
|
onRecipientChipsChange: { transform: async (chips: unknown) => chips },
|
||||||
},
|
},
|
||||||
contactHooks: {
|
contactHooks: {
|
||||||
search: { call: async () => [] },
|
search: { call: async () => [] },
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
import { unlink, writeFileSync } from "fs";
|
import { mkdtempSync, unlink, writeFileSync } from "fs";
|
||||||
|
import { tmpdir } from "node:os";
|
||||||
|
import path from "node:path";
|
||||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||||
|
|
||||||
|
// The route consults admin-dashboard overrides (ADMIN_CONFIG_DIR, default
|
||||||
|
// data/admin) before env vars. Point it at an empty temp dir so local admin
|
||||||
|
// state on the developer's machine can't leak into these env-driven
|
||||||
|
// assertions. Must happen before the first GET, because the config manager
|
||||||
|
// singleton loads the directory once and caches it.
|
||||||
|
process.env.ADMIN_CONFIG_DIR = mkdtempSync(path.join(tmpdir(), 'bw-config-route-'));
|
||||||
|
|
||||||
// Mock NextResponse before importing the route
|
// Mock NextResponse before importing the route
|
||||||
vi.mock('next/server', () => ({
|
vi.mock('next/server', () => ({
|
||||||
NextResponse: {
|
NextResponse: {
|
||||||
|
|||||||
@@ -302,6 +302,11 @@ describe('JMAPClient resilience', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('does not mark the connection lost or reconnect repeatedly while rate limited', async () => {
|
it('does not mark the connection lost or reconnect repeatedly while rate limited', async () => {
|
||||||
|
// The file-level shouldAdvanceTime lets fake time creep forward with
|
||||||
|
// the wall clock, which can fire the 30s keep-alive an extra time on a
|
||||||
|
// slow or loaded machine. This test counts pings, so pin the clock and
|
||||||
|
// advance it explicitly.
|
||||||
|
vi.useFakeTimers({ shouldAdvanceTime: false });
|
||||||
const client = await createConnectedClient();
|
const client = await createConnectedClient();
|
||||||
const callback = vi.fn();
|
const callback = vi.fn();
|
||||||
client.onConnectionChange(callback);
|
client.onConnectionChange(callback);
|
||||||
|
|||||||
@@ -247,18 +247,18 @@ describe('contact-store', () => {
|
|||||||
expect(results.length).toBeLessThanOrEqual(10);
|
expect(results.length).toBeLessThanOrEqual(10);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should expand group members when group name matches', () => {
|
it('should suggest a matching group as a single entry with member count', () => {
|
||||||
const member1 = makeContact({ id: 'm1', name: { components: [{ kind: 'given', value: 'Alice' }], isOrdered: true }, emails: { e0: { address: 'alice@test.com' } } });
|
const member1 = makeContact({ id: 'm1', name: { components: [{ kind: 'given', value: 'Alice' }], isOrdered: true }, emails: { e0: { address: 'alice@test.com' } } });
|
||||||
const member2 = makeContact({ id: 'm2', name: { components: [{ kind: 'given', value: 'Bob' }], isOrdered: true }, emails: { e0: { address: 'bob@test.com' } } });
|
const member2 = makeContact({ id: 'm2', name: { components: [{ kind: 'given', value: 'Bob' }], isOrdered: true }, emails: { e0: { address: 'bob@test.com' } } });
|
||||||
const group = makeGroup({ id: 'g1', members: { m1: true, m2: true } });
|
const group = makeGroup({ id: 'g1', members: { m1: true, m2: true } });
|
||||||
useContactStore.setState({ contacts: [member1, member2, group] });
|
useContactStore.setState({ contacts: [member1, member2, group] });
|
||||||
|
|
||||||
const results = useContactStore.getState().getAutocomplete('Team');
|
const results = useContactStore.getState().getAutocomplete('Team');
|
||||||
expect(results).toHaveLength(2);
|
expect(results).toHaveLength(1);
|
||||||
expect(results.map(r => r.email).sort()).toEqual(['alice@test.com', 'bob@test.com']);
|
expect(results[0]).toEqual({ name: 'Team', email: '', group: { id: 'g1', memberCount: 2 } });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not include group itself in results', () => {
|
it('should not suggest a group with no addressable members', () => {
|
||||||
const group = makeGroup({ id: 'g1' });
|
const group = makeGroup({ id: 'g1' });
|
||||||
useContactStore.setState({ contacts: [group] });
|
useContactStore.setState({ contacts: [group] });
|
||||||
const results = useContactStore.getState().getAutocomplete('Team');
|
const results = useContactStore.getState().getAutocomplete('Team');
|
||||||
|
|||||||
+5
-3
@@ -9,9 +9,11 @@ export default defineConfig({
|
|||||||
globals: true,
|
globals: true,
|
||||||
setupFiles: ['./vitest.setup.ts'],
|
setupFiles: ['./vitest.setup.ts'],
|
||||||
// integration/** is the dockerized Playwright suite (run via
|
// integration/** is the dockerized Playwright suite (run via
|
||||||
// `npm run test:integration`); examples/** is untracked sample code. Both
|
// `npm run test:integration`); examples/** is untracked sample code; and
|
||||||
// use their own runners and must not be collected by vitest.
|
// repos/** holds sibling checkouts with their own runners. node_modules
|
||||||
exclude: ['e2e/**', 'integration/**', 'examples/**', 'node_modules/**', '.next/**'],
|
// must be globbed at any depth or the nested repos/*/node_modules trees
|
||||||
|
// get collected too.
|
||||||
|
exclude: ['e2e/**', 'integration/**', 'examples/**', 'repos/**', '**/node_modules/**', '.next/**'],
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
|
|||||||
Reference in New Issue
Block a user