|
1 | 1 | import { describe, it, expect, vi } from 'vitest'; |
2 | 2 | import { render, screen } from '@testing-library/react'; |
3 | 3 | import React from 'react'; |
| 4 | +import * as ObjectUIReact from '@object-ui/react'; |
4 | 5 | import { ObjectCalendarRenderer } from './index'; |
5 | 6 |
|
6 | | -// Mock dependencies |
7 | | -vi.mock('@object-ui/react', async () => { |
8 | | - const React = await import('react'); |
9 | | - return { |
10 | | - useSchemaContext: vi.fn(() => ({ dataSource: { type: 'mock-datasource' } })), |
11 | | - SchemaRendererContext: React.createContext(null), |
12 | | - }; |
13 | | -}); |
| 7 | +// Partial mock — override ONLY what this test controls, keep every other real |
| 8 | +// export (objectui#3219). |
| 9 | +// |
| 10 | +// A whole-module `vi.mock('@object-ui/react', () => ({ ... }))` used to list |
| 11 | +// just `useSchemaContext` + `SchemaRendererContext`. That made the file's |
| 12 | +// result depend on HOW the module graph resolved, so the two vitest configs in |
| 13 | +// this repo disagreed about it: |
| 14 | +// |
| 15 | +// - root `vitest.config.mts` (what CI runs): this file is in `heavyDomTests`, |
| 16 | +// and `vitest.setup.dom.tsx` eagerly imports `@object-ui/components`. That |
| 17 | +// evaluates `components/src/hooks/related-count-store.ts` — which imports |
| 18 | +// `subscribeDataChanges` from `@object-ui/react` — against the REAL module |
| 19 | +// before the mock applies. Green, by accident. |
| 20 | +// - `packages/plugin-calendar/vitest.config.ts` (what `pnpm --filter … test` |
| 21 | +// and `turbo run test` run): no such setup, so `@object-ui/components` is |
| 22 | +// first evaluated inside the mocked graph. Vitest 4 hard-errors on a |
| 23 | +// missing export instead of silently yielding `undefined`, so the suite |
| 24 | +// failed to load at all: `No "subscribeDataChanges" export is defined on |
| 25 | +// the "@object-ui/react" mock`. |
| 26 | +// |
| 27 | +// Spreading `importOriginal()` removes the sensitivity: the mock is a superset |
| 28 | +// of the real module under either resolution, so a transitive consumer can |
| 29 | +// never trip over an export this test never intended to replace. Adding a new |
| 30 | +// `@object-ui/react` export can no longer break this file. |
| 31 | +vi.mock(import('@object-ui/react'), async (importOriginal) => ({ |
| 32 | + ...(await importOriginal()), |
| 33 | + // Only the pieces this test drives: |
| 34 | + useSchemaContext: vi.fn(() => ({ dataSource: { type: 'mock-datasource' } })), |
| 35 | +})); |
14 | 36 |
|
15 | | -// Mock the implementation |
| 37 | +// Mock the implementation. Deliberate whole-module replacement of a LOCAL |
| 38 | +// module: stubbing `ObjectCalendar` is the isolation boundary this test is |
| 39 | +// about, and `./ObjectCalendar`'s only runtime export is the component itself |
| 40 | +// (`ObjectCalendarProps` is type-only and erased at runtime). |
16 | 41 | vi.mock('./ObjectCalendar', () => ({ |
17 | 42 | ObjectCalendar: ({ dataSource, data, loading }: any) => ( |
18 | 43 | <div data-testid="calendar-mock"> |
@@ -42,4 +67,27 @@ describe('Plugin Calendar Registration', () => { |
42 | 67 | expect(el).toHaveTextContent('Data: [{"id":1,"name":"Event A"}]'); |
43 | 68 | expect(el).toHaveTextContent('Loading: false'); |
44 | 69 | }); |
| 70 | + |
| 71 | + // Regression guard for objectui#3219 — keep this test. |
| 72 | + // |
| 73 | + // It pins the exact invariant whose absence made the root config and the |
| 74 | + // package config disagree about this file: the `@object-ui/react` mock must |
| 75 | + // expose every export the real module has. When that holds, no transitive |
| 76 | + // importer of `@object-ui/react` can hit a missing export, so the file |
| 77 | + // behaves identically no matter which config resolved the module (source via |
| 78 | + // the root alias, or `dist` via the package config) and no matter whether a |
| 79 | + // setup file happened to pre-load the consumer first. |
| 80 | + // |
| 81 | + // Deliberately compares export SETS rather than naming `subscribeDataChanges`: |
| 82 | + // naming the one export that broke would just re-arm the same trap for the |
| 83 | + // next export somebody adds. |
| 84 | + it('mocks @object-ui/react as a superset of the real module (pins both run paths to the same result)', async () => { |
| 85 | + const actual = await vi.importActual<typeof ObjectUIReact>('@object-ui/react'); |
| 86 | + |
| 87 | + const missing = Object.keys(actual) |
| 88 | + .filter((name) => !(name in ObjectUIReact)) |
| 89 | + .sort(); |
| 90 | + |
| 91 | + expect(missing).toEqual([]); |
| 92 | + }); |
45 | 93 | }); |
0 commit comments