@cognite/dune 0.3.5 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,7 +7,8 @@ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>AGENTS.md'
7
7
 
8
8
  Inject dependencies via React context (hooks/components) or factory-override pattern (plain functions). Never hard-code dependencies.
9
9
 
10
- **React context**
10
+ ### React context
11
+
11
12
  ```typescript
12
13
  const defaultDeps = { useDataSource, useAnalytics };
13
14
  export type MyHookContextType = typeof defaultDeps;
@@ -18,7 +19,8 @@ export function useMyHook() {
18
19
  }
19
20
  ```
20
21
 
21
- **Factory overrides**
22
+ ### Factory overrides
23
+
22
24
  ```typescript
23
25
  type Deps = { serviceFactory: () => SomeService };
24
26
  const defaultDeps: Deps = { serviceFactory: () => new SomeServiceImpl() };
@@ -40,7 +42,9 @@ export interface DataService {
40
42
  save(data: Data): Promise<void>;
41
43
  }
42
44
 
43
- export class ApiDataService implements DataService { /* ... */ }
45
+ export class ApiDataService implements DataService {
46
+ /* ... */
47
+ }
44
48
  ```
45
49
 
46
50
  ---
@@ -53,51 +57,89 @@ Business logic lives in `use<Name>ViewModel`. Components only render.
53
57
  export function useTodoViewModel(): TodoViewModel {
54
58
  const { useTodoStorage, addTodoCommand } = useContext(TodoViewModelContext);
55
59
  const storage = useTodoStorage();
56
- const addTodo = useCallback((text: string) => addTodoCommand(text, storage), [storage, addTodoCommand]);
60
+ const addTodo = useCallback(
61
+ (text: string) => addTodoCommand(text, storage),
62
+ [storage, addTodoCommand]
63
+ );
57
64
  return { todos: storage.listAllTodos(), addTodo };
58
65
  }
59
66
 
60
67
  export const TodoView = () => {
61
68
  const { todos, addTodo } = useTodoViewModel();
62
- return <ul>{todos.map(t => <TodoItem key={t.id} todo={t} onAdd={addTodo} />)}</ul>;
69
+ return <ul>{todos.map((t) => <TodoItem key={t.id} todo={t} onAdd={addTodo} />)}</ul>;
63
70
  };
64
71
  ```
65
72
 
66
73
  ---
67
74
 
68
- ## 4. Test-Driven Development
75
+ ## 4. Test-First Development
76
+
77
+ Write tests before implementation for all non-trivial behavior changes.
69
78
 
70
- ### File creation order
71
- 1. Integration tests
72
- 2. Unit tests
79
+ ### Preferred order
80
+
81
+ Start with behavior-focused tests so requirements are specified before implementation details:
82
+
83
+ 1. Integration tests (user-visible behavior)
84
+ 2. Unit tests (isolated module logic)
73
85
  3. Source files to make tests pass
74
86
 
87
+ For bug fixes, start by adding a failing regression test that reproduces the issue.
88
+
89
+ Every new module with logic (service, hook, component, utility) must include a corresponding `*.test.ts(x)` file in the same changeset.
90
+
91
+ ### Reasonable exceptions
92
+
93
+ - Bootstrapping/entry files (for example `main.tsx`)
94
+ - Generated code
95
+ - Trivial pure-markup components with no logic or state
96
+
97
+ ### Test levels in this repo
98
+
99
+ - **Integration test**: validates behavior across boundaries (for example component + view model + service contract), mocking only external systems such as network APIs.
100
+ - **Unit test**: validates one module in isolation (service, hook, utility, or component behavior).
101
+
102
+ ### Minimum expected coverage by file type
103
+
104
+ | File type | Required test cases |
105
+ | --- | --- |
106
+ | Service (`*Service.ts`) | Correct request construction; response parsing; error thrown on non-OK status |
107
+ | ViewModel hook (`use*ViewModel.ts`) | Loading state; success state with correct derived values; error state |
108
+ | Pure utility / helper | Every exported function and all meaningful branches |
109
+ | View component | Renders expected content from props; loading/error/empty states where applicable |
110
+
75
111
  ### Conventions
76
- - Files: `*.test.ts(x)` — runner: **Vitest** (`pnpm test` to run all, `vitest run` within a package)
77
- - Structure: Arrange / Act / Assert (explicit comments when test > ~10 statements)
78
- - One behavior per test; helper functions at the bottom of the file
79
- - Prefer context injection over `vi.mock`; always add a comment when `vi.mock` is unavoidable
112
+
113
+ - Files: `*.test.ts(x)`; runner: **Vitest** (`pnpm test` or `vitest run`)
114
+ - Structure: Arrange / Act / Assert (add explicit comments for longer tests)
115
+ - One behavior per test
116
+ - Keep helper functions at the bottom of the file
117
+ - Prefer dependency/context injection over `vi.mock`; add a short reason when `vi.mock` is unavoidable
80
118
 
81
119
  ### Type-safe mocks
120
+
82
121
  ```typescript
83
122
  // Preferred: vi.fn(() => ...) for consistent behavior
84
123
  mockContext = { useUserInfo: vi.fn(() => ({ data: mockUser, isFetched: true })) };
85
124
 
86
- // For per-test reconfiguration
125
+ // Per-test reconfiguration
87
126
  mockContext = { useUserInfo: vi.fn() };
88
127
  vi.mocked(mockContext.useUserInfo).mockReturnValue({ data: undefined, isFetched: true });
89
128
  ```
90
129
 
91
- For full interface mocks, use `assert.fail` on methods the unit under test should never call or better, use narrow interfaces that only expose what is needed.
130
+ For full interface mocks, use `assert.fail` on methods the unit under test should never call, or preferably define a narrower interface.
92
131
 
93
132
  ```typescript
94
133
  mockStorage = {
95
134
  list: vi.fn(),
96
- retrieve: vi.fn(() => { assert.fail('Not implemented'); }),
135
+ retrieve: vi.fn(() => {
136
+ assert.fail('Not implemented');
137
+ }),
97
138
  };
98
139
  ```
99
140
 
100
- ### React hooks
141
+ ### React hook test pattern
142
+
101
143
  ```typescript
102
144
  describe(useMyHook.name, () => {
103
145
  let mockContext: MyContextType;
@@ -112,25 +154,29 @@ describe(useMyHook.name, () => {
112
154
 
113
155
  it('should ...', async () => {
114
156
  const { result } = renderHook(() => useMyHook(), { wrapper });
115
-
116
- await act(async () => { await result.current.someAction(); });
117
-
157
+ await act(async () => {
158
+ await result.current.someAction();
159
+ });
118
160
  await waitFor(() => expect(result.current.isLoading).toBe(false));
119
161
  });
120
162
  });
121
163
  ```
122
164
 
123
- ### Type rules
124
- - Never use `any` — prefer `unknown` or strong types
125
- - No `as unknown as T` casts; for partial mocks use `{ ...defaults, ...overrides } as T`
165
+ ### Shared mock data
166
+
167
+ Place reusable factories in `src/__mocks__/`. Use `.test` TLD for fake URLs (RFC 2606).
168
+
169
+ ---
170
+
171
+ ## 5. TypeScript Rules
172
+
173
+ - Never use `any`; prefer `unknown` or explicit strong types
174
+ - Never use `as unknown as T`; for partial test doubles use `{ ...defaults, ...overrides } as T`
175
+ - Use direct React type imports: `import type { ComponentType, ReactNode } from 'react'`
126
176
 
127
177
  ```typescript
128
178
  function createMockWindow(overrides: Partial<Window> = {}): Window {
129
179
  return { postMessage: vi.fn(), ...overrides } as Window;
130
180
  }
131
181
  ```
132
-
133
- - Use direct React type imports: `import type { ComponentType, ReactNode } from 'react'`
134
-
135
- ### Shared mock data
136
- Place reusable factories in `src/__mocks__/`. Use `.test` TLD for fake URLs (RFC 2606).
182
+ ---
@@ -23,7 +23,7 @@ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>package.json'
23
23
  "dependencies": {
24
24
  "@cognite/aura": "^0.1.4",
25
25
  "@cognite/sdk": "^10.3.0",
26
- "@cognite/dune": "^0.3.5",
26
+ "@cognite/dune": "^0.3.6",
27
27
  "@tabler/icons-react": "^3.35.0",
28
28
  "@tanstack/react-query": "^5.90.10",
29
29
  "clsx": "^2.1.1",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cognite/dune",
3
- "version": "0.3.5",
3
+ "version": "0.3.6",
4
4
  "description": "Build and deploy React apps to Cognite Data Fusion",
5
5
  "keywords": ["cognite", "dune", "cdf", "fusion", "react", "scaffold", "deploy"],
6
6
  "license": "Apache-2.0",