@cognite/cli 0.5.2 → 0.6.0-alpha.8

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.
Files changed (46) hide show
  1. package/README.md +118 -33
  2. package/_templates/app/new/config/eslint.config.mjs.ejs.t +99 -0
  3. package/_templates/app/new/config/tsconfig.json.ejs.t +35 -0
  4. package/_templates/app/new/config/tsconfig.node.json.ejs.t +27 -0
  5. package/_templates/app/new/config/vite.config.ts.ejs.t +26 -0
  6. package/_templates/app/new/config/vitest.config.ts.ejs.t +14 -0
  7. package/_templates/app/new/config/vitest.setup.ts.ejs.t +4 -0
  8. package/_templates/app/new/cursor/data-modeling.mdc.ejs.t +1996 -0
  9. package/_templates/app/new/cursor/mcp.json.ejs.t +10 -0
  10. package/_templates/app/new/cursor/rules.mdc.ejs.t +10 -0
  11. package/_templates/app/new/github/ci.yml.ejs.t +36 -0
  12. package/_templates/app/new/prompt.js +49 -0
  13. package/_templates/app/new/root/.npmrc.ejs.t +4 -0
  14. package/_templates/app/new/root/AGENTS.md.ejs.t +215 -0
  15. package/_templates/app/new/root/SPEC.md.ejs.t +77 -0
  16. package/_templates/app/new/root/app.json.ejs.t +22 -0
  17. package/_templates/app/new/root/gitignore.ejs.t +21 -0
  18. package/_templates/app/new/root/index.html.ejs.t +36 -0
  19. package/_templates/app/new/root/package.json.ejs.t +67 -0
  20. package/_templates/app/new/src/App.test.tsx.ejs.t +45 -0
  21. package/_templates/app/new/src/App.tsx.ejs.t +265 -0
  22. package/_templates/app/new/src/lib/utils.ts.ejs.t +9 -0
  23. package/_templates/app/new/src/main.tsx.ejs.t +36 -0
  24. package/_templates/app/new/src/styles.css.ejs.t +12 -0
  25. package/_vendor/spec-kit/.version +4 -0
  26. package/_vendor/spec-kit/README.md +39 -0
  27. package/_vendor/spec-kit/commands/speckit.analyze.md +249 -0
  28. package/_vendor/spec-kit/commands/speckit.checklist.md +361 -0
  29. package/_vendor/spec-kit/commands/speckit.clarify.md +247 -0
  30. package/_vendor/spec-kit/commands/speckit.implement.md +198 -0
  31. package/_vendor/spec-kit/commands/speckit.plan.md +149 -0
  32. package/_vendor/spec-kit/commands/speckit.specify.md +327 -0
  33. package/_vendor/spec-kit/commands/speckit.tasks.md +200 -0
  34. package/_vendor/spec-kit/scripts/bash/check-prerequisites.sh +190 -0
  35. package/_vendor/spec-kit/scripts/bash/common.sh +645 -0
  36. package/_vendor/spec-kit/scripts/bash/setup-plan.sh +75 -0
  37. package/_vendor/spec-kit/templates/checklist-template.md +40 -0
  38. package/_vendor/spec-kit/templates/plan-template.md +104 -0
  39. package/_vendor/spec-kit/templates/spec-template.md +128 -0
  40. package/_vendor/spec-kit/templates/tasks-template.md +251 -0
  41. package/dist/chunk-GFMJ4MJZ.js +8 -0
  42. package/dist/cli/cli.js +347 -0
  43. package/dist/skills-4R3OUI44.js +2 -0
  44. package/package.json +25 -17
  45. package/index.js +0 -116
  46. package/operations.js +0 -113
@@ -0,0 +1,10 @@
1
+ ---
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>.cursor/mcp.json'
3
+ ---
4
+ {
5
+ "mcpServers": {
6
+ "cdf-datamodeling-mcp": {
7
+ "command": "npx cdf-datamodelling-mcp-server"
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,10 @@
1
+ ---
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>.cursor/rules/rules.mdc'
3
+ ---
4
+ ---
5
+ description: Describes global rules
6
+ alwaysApply: true
7
+ ---
8
+
9
+ - Use direct `@cognite/aura/components` exports whenever Aura provides the component you need. Fall back to custom markup only when Aura does not expose an equivalent primitive.
10
+ - Follow the SPEC.md handling rules in `AGENTS.md` §0.
@@ -0,0 +1,36 @@
1
+ ---
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>.github/workflows/ci.yml'
3
+ ---
4
+ name: CI
5
+
6
+ on:
7
+ pull_request:
8
+ push:
9
+ branches:
10
+ - main
11
+
12
+ jobs:
13
+ lint-test-build:
14
+ runs-on: ubuntu-latest
15
+
16
+ steps:
17
+ - name: Checkout
18
+ uses: actions/checkout@v6
19
+
20
+ - name: Setup Node
21
+ uses: actions/setup-node@v6
22
+ with:
23
+ node-version: 24
24
+ cache: npm
25
+
26
+ - name: Install dependencies
27
+ run: npm install
28
+
29
+ - name: Lint
30
+ run: npm run lint
31
+
32
+ - name: Test
33
+ run: npm test
34
+
35
+ - name: Build
36
+ run: npm run build
@@ -0,0 +1,49 @@
1
+ export default [
2
+ {
3
+ type: 'input',
4
+ name: 'name',
5
+ message: 'What is the app name? (use kebab-case, e.g., my-awesome-app)',
6
+ initial: 'my-dune-app',
7
+ validate: (input) =>
8
+ /^[a-z][a-z0-9-]*$/.test(input)
9
+ ? true
10
+ : 'App name must be kebab-case (lowercase, hyphens only)',
11
+ },
12
+ {
13
+ type: 'input',
14
+ name: 'displayName',
15
+ message: 'What is the display name? (e.g., My Awesome App)',
16
+ initial: 'My Dune app',
17
+ },
18
+ {
19
+ type: 'input',
20
+ name: 'description',
21
+ message: 'What is the app description?',
22
+ initial: 'A Dune application',
23
+ },
24
+ {
25
+ type: 'input',
26
+ name: 'org',
27
+ message: 'Deployment org? (e.g., cog-demo, cog-atlas)',
28
+ initial: 'cog-demo',
29
+ },
30
+ {
31
+ type: 'input',
32
+ name: 'project',
33
+ message: 'Deployment project? (e.g., lervik-industries, atlas-greenfield)',
34
+ initial: 'lervik-industries',
35
+ },
36
+ {
37
+ type: 'input',
38
+ name: 'cluster',
39
+ message: 'Cluster? (e.g., greenfield, westeurope-1, api)',
40
+ initial: 'api',
41
+ },
42
+ {
43
+ type: 'input',
44
+ name: 'baseUrl',
45
+ // initial is set dynamically in create-prompter based on the cluster answer
46
+ message: 'Base URL? (e.g. https://az-arn-004.cognitedata.com)',
47
+ initial: 'https://api.cognitedata.com',
48
+ },
49
+ ];
@@ -0,0 +1,4 @@
1
+ ---
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>.npmrc'
3
+ ---
4
+ engine-strict=true
@@ -0,0 +1,215 @@
1
+ ---
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>AGENTS.md'
3
+ ---
4
+ # Coding Standards
5
+
6
+ <% if (useSpecKit) { -%>
7
+ ## 0. Product Spec (spec-driven development)
8
+
9
+ This app uses [github/spec-kit](https://github.com/github/spec-kit) for spec-driven development. Specs live under `specs/<NNN>-<feature-name>/spec.md`, one directory per feature.
10
+
11
+ - To start a new feature, run `/speckit.specify <description>` in Claude Code or Cursor. It generates a properly numbered feature directory and a spec to fill in. Then run `/speckit.clarify` → `/speckit.plan` → `/speckit.tasks` → `/speckit.implement`.
12
+ - When user-visible behavior changes in an existing feature, update its `specs/<NNN>-<feature>/spec.md` before or alongside the code change.
13
+ - When a feature touches Cognite Data Fusion data, the spec must document existing CDF views read from, new views needed, and spaces used.
14
+ <% } else { -%>
15
+ ## 0. Product Spec (SPEC.md)
16
+
17
+ `SPEC.md` at the repo root is the living product spec for this app. Read it before making feature decisions, and keep it in sync with user-visible behavior.
18
+
19
+ - If `SPEC.md` is empty or contains only commented `<!-- -->` placeholders, proactively offer to populate it before writing implementation code. Do not silently skip.
20
+ - When user-visible behavior changes, update the relevant `SPEC.md` section before or alongside the code change.
21
+ <% } -%>
22
+
23
+ ---
24
+
25
+ ## 1. Dependency Injection
26
+
27
+ Inject dependencies via React context (hooks/components) or factory-override pattern (plain functions). Never hard-code dependencies.
28
+
29
+ ### React context
30
+
31
+ ```typescript
32
+ const defaultDeps = { useDataSource, useAnalytics };
33
+ export type MyHookContextType = typeof defaultDeps;
34
+ export const MyHookContext = createContext<MyHookContextType>(defaultDeps);
35
+
36
+ export function useMyHook() {
37
+ const { useDataSource } = useContext(MyHookContext);
38
+ }
39
+ ```
40
+
41
+ ### Factory overrides
42
+
43
+ ```typescript
44
+ type Deps = { serviceFactory: () => SomeService };
45
+ const defaultDeps: Deps = { serviceFactory: () => new SomeServiceImpl() };
46
+
47
+ export const doWork = async (props: Props, overrides?: Partial<Deps>) => {
48
+ const { serviceFactory } = { ...defaultDeps, ...overrides };
49
+ };
50
+ ```
51
+
52
+ ---
53
+
54
+ ## 2. Interface-Based Services
55
+
56
+ Define an interface; implement with a class. Never reference the concrete class outside its own file.
57
+
58
+ ```typescript
59
+ export interface DataService {
60
+ load(): Promise<Data>;
61
+ save(data: Data): Promise<void>;
62
+ }
63
+
64
+ export class ApiDataService implements DataService {
65
+ /* ... */
66
+ }
67
+ ```
68
+
69
+ ---
70
+
71
+ ## 3. ViewModel Pattern
72
+
73
+ Business logic lives in `use<Name>ViewModel`. Components only render.
74
+
75
+ ```typescript
76
+ export function useTodoViewModel(): TodoViewModel {
77
+ const { useTodoStorage, addTodoCommand } = useContext(TodoViewModelContext);
78
+ const storage = useTodoStorage();
79
+ const addTodo = useCallback(
80
+ (text: string) => addTodoCommand(text, storage),
81
+ [storage, addTodoCommand]
82
+ );
83
+ return { todos: storage.listAllTodos(), addTodo };
84
+ }
85
+
86
+ export const TodoView = () => {
87
+ const { todos, addTodo } = useTodoViewModel();
88
+ return <ul>{todos.map((t) => <TodoItem key={t.id} todo={t} onAdd={addTodo} />)}</ul>;
89
+ };
90
+ ```
91
+
92
+ ---
93
+
94
+ ## 4. Test-First Development
95
+
96
+ Write tests before implementation for all non-trivial behavior changes.
97
+
98
+ ### Preferred order
99
+
100
+ Start with behavior-focused tests so requirements are specified before implementation details:
101
+
102
+ 1. Integration tests (user-visible behavior)
103
+ 2. Unit tests (isolated module logic)
104
+ 3. Source files to make tests pass
105
+
106
+ For bug fixes, start by adding a failing regression test that reproduces the issue.
107
+
108
+ Every new module with logic (service, hook, component, utility) must include a corresponding `*.test.ts(x)` file in the same changeset.
109
+
110
+ ### Reasonable exceptions
111
+
112
+ - Bootstrapping/entry files (for example `main.tsx`)
113
+ - Generated code
114
+ - Trivial pure-markup components with no logic or state
115
+
116
+ ### Test levels in this repo
117
+
118
+ - **Integration test**: validates behavior across boundaries (for example component + view model + service contract), mocking only external systems such as network APIs.
119
+ - **Unit test**: validates one module in isolation (service, hook, utility, or component behavior).
120
+
121
+ ### Minimum expected coverage by file type
122
+
123
+ | File type | Required test cases |
124
+ | --- | --- |
125
+ | Service (`*Service.ts`) | Correct request construction; response parsing; error thrown on non-OK status |
126
+ | ViewModel hook (`use*ViewModel.ts`) | Loading state; success state with correct derived values; error state |
127
+ | Pure utility / helper | Every exported function and all meaningful branches |
128
+ | View component | Renders expected content from props; loading/error/empty states where applicable |
129
+
130
+ ### Conventions
131
+
132
+ - Files: `*.test.ts(x)`; runner: **Vitest** (`npm test` or `vitest run`)
133
+ - Structure: Arrange / Act / Assert (add explicit comments for longer tests)
134
+ - One behavior per test
135
+ - Keep helper functions at the bottom of the file
136
+ - Prefer dependency/context injection over `vi.mock`; add a short reason when `vi.mock` is unavoidable
137
+
138
+ ### Type-safe mocks
139
+
140
+ ```typescript
141
+ // Preferred: vi.fn(() => ...) for consistent behavior
142
+ mockContext = { useUserInfo: vi.fn(() => ({ data: mockUser, isFetched: true })) };
143
+
144
+ // Per-test reconfiguration
145
+ mockContext = { useUserInfo: vi.fn() };
146
+ vi.mocked(mockContext.useUserInfo).mockReturnValue({ data: undefined, isFetched: true });
147
+ ```
148
+
149
+ For full interface mocks, use `assert.fail` on methods the unit under test should never call, or preferably define a narrower interface.
150
+
151
+ ```typescript
152
+ mockStorage = {
153
+ list: vi.fn(),
154
+ retrieve: vi.fn(() => {
155
+ assert.fail('Not implemented');
156
+ }),
157
+ };
158
+ ```
159
+
160
+ ### React hook test pattern
161
+
162
+ ```typescript
163
+ describe(useMyHook.name, () => {
164
+ let mockContext: MyContextType;
165
+ let wrapper: ComponentType<{ children: ReactNode }>;
166
+
167
+ beforeEach(() => {
168
+ mockContext = { useUserInfo: vi.fn(() => ({ data: mockUser })) };
169
+ wrapper = ({ children }) => (
170
+ <MyHookContext.Provider value={mockContext}>{children}</MyHookContext.Provider>
171
+ );
172
+ });
173
+
174
+ it('should ...', async () => {
175
+ const { result } = renderHook(() => useMyHook(), { wrapper });
176
+ await act(async () => {
177
+ await result.current.someAction();
178
+ });
179
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
180
+ });
181
+ });
182
+ ```
183
+
184
+ ### Shared mock data
185
+
186
+ Place reusable factories in `src/__mocks__/`. Use `.test` TLD for fake URLs (RFC 2606).
187
+
188
+ ---
189
+
190
+ ## 5. TypeScript Rules
191
+
192
+ - Never use `any`; prefer `unknown` or explicit strong types
193
+ - Never use `as unknown as T`; for partial test doubles use `{ ...defaults, ...overrides } as T`
194
+ - Use direct React type imports: `import type { ComponentType, ReactNode } from 'react'`
195
+
196
+ ```typescript
197
+ function createMockWindow(overrides: Partial<Window> = {}): Window {
198
+ return { postMessage: vi.fn(), ...overrides } as Window;
199
+ }
200
+ ```
201
+
202
+ ---
203
+
204
+ ## 6. Commits and pull requests
205
+
206
+ Use [Conventional Commits v1.0.0](https://www.conventionalcommits.org/en/v1.0.0/).
207
+
208
+ - Commit in **small, buildable steps** while lint and tests remain green for this repo. Split **unrelated** edits into separate commits before opening a pull request.
209
+ - **Subject line:** `type[(scope)][!]: description` — imperative mood, no trailing period, blank line before an optional body. Use `!` before `:` and/or a **`BREAKING CHANGE:`** footer for incompatible changes (full rules in the link above).
210
+ - **Types** (pick the narrowest match): `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`. **Scope:** optional short area (`auth`, `chat`, `deps`); omit if it would be vague.
211
+ - **Body:** only for non-obvious motivation or behaviour; keep it short and do not repeat the diff. **Footers** (for example `Fixes #123`) when this project tracks issues that way.
212
+ - **Pull requests:** title and **Summary** should match the same vocabulary; do not replace conventional commits with only a PR headline.
213
+ - Before committing: review **`git status`** and **`git diff`** (including staged); unstage and commit separately if the index mixes unrelated concerns.
214
+
215
+ ---
@@ -0,0 +1,77 @@
1
+ ---
2
+ to: '<%= useSpecKit ? null : (useCurrentDir ? "" : ((directoryName || name) + "/")) + "SPEC.md" %>'
3
+ ---
4
+ # Feature Specification: <%= displayName || name %>
5
+
6
+ <!--
7
+ This is your app's living product spec. Edit it directly or ask your coding
8
+ agent to collaborate with you on it.
9
+ -->
10
+
11
+ ## User Scenarios & Testing
12
+
13
+ ### User Stories
14
+
15
+ <!-- 1. As a [persona], I want [capability], so that [benefit]. -->
16
+
17
+ ### Acceptance Scenarios
18
+
19
+ <!-- - Given [state], when [action], then [outcome]. -->
20
+
21
+ ## Requirements
22
+
23
+ ### Functional Requirements
24
+
25
+ <!--
26
+ List numbered functional requirements (FR-001, FR-002, …) so plans and tasks
27
+ can reference them.
28
+ -->
29
+
30
+ <!-- - FR-001: System MUST … -->
31
+
32
+ ## Success Criteria
33
+
34
+ <!--
35
+ Measurable outcomes that signal the feature is working. Prefer user-visible
36
+ criteria over implementation details.
37
+ -->
38
+
39
+ <!-- - SC-001: Users complete X in under N seconds 95% of the time. -->
40
+
41
+ ## Clarifications
42
+
43
+ <!--
44
+ Open questions or ambiguities that need to be resolved before planning.
45
+ `/speckit.clarify` can help surface these.
46
+ -->
47
+
48
+ ## Assumptions
49
+
50
+ <!-- - [Mobile support is out of scope for v1] -->
51
+
52
+ ---
53
+
54
+ ## Data Models & CDF Integration *(Dune-specific, mandatory)*
55
+
56
+ <!--
57
+ Dune-specific section. Capture how this app integrates with Cognite Data
58
+ Fusion data models. Every Dune app should fill this in.
59
+ -->
60
+
61
+ ### Existing views
62
+
63
+ <!--
64
+ CDF views this app reads from. Format: `<space>.<view>:<version>`.
65
+ -->
66
+
67
+ ### New views
68
+
69
+ <!--
70
+ Views this app needs that don't yet exist. Describe properties and relationships.
71
+ -->
72
+
73
+ ### Spaces
74
+
75
+ <!--
76
+ CDF spaces this app uses, and what each contains.
77
+ -->
@@ -0,0 +1,22 @@
1
+ ---
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>app.json'
3
+ ---
4
+ {
5
+ "name": "<%= displayName %>",
6
+ "description": "<%= description %>",
7
+ "externalId": "<%= name %>",
8
+ "versionTag": "0.0.1",
9
+ <% if (infra === 'appsApi') { -%>
10
+ "infra": "appsApi",
11
+ <% } -%>
12
+ "deployments": [
13
+ {
14
+ "org": "<%= org %>",
15
+ "project": "<%= project %>",
16
+ "baseUrl": "<%= baseUrl %>",
17
+ "published": false,
18
+ "deployClientId": "",
19
+ "deploySecretName": "<%= org %>_<%= project %>_<%= cluster %>"
20
+ }
21
+ ]
22
+ }
@@ -0,0 +1,21 @@
1
+ ---
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>.gitignore'
3
+ ---
4
+ # Dependencies
5
+ node_modules
6
+
7
+ # Build output
8
+ dist
9
+
10
+ # Environment variables
11
+ .env
12
+ .env.local
13
+
14
+ # Editor directories
15
+ .vscode
16
+ .idea
17
+
18
+ # OS files
19
+ .DS_Store
20
+ Thumbs.db
21
+
@@ -0,0 +1,36 @@
1
+ ---
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>index.html'
3
+ ---
4
+ <!DOCTYPE html>
5
+ <html lang="en">
6
+ <head>
7
+ <meta charset="UTF-8" />
8
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
9
+ <meta
10
+ name="viewport"
11
+ content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
12
+ />
13
+ <meta name="theme-color" content="#000000" />
14
+ <meta name="description" content="Cognite Data Fusion Application" />
15
+ <meta name="apple-mobile-web-app-capable" content="yes" />
16
+ <meta name="apple-mobile-web-app-status-bar-style" content="default" />
17
+ <meta name="apple-mobile-web-app-title" content="CDF Application" />
18
+ <title><%= displayName %></title>
19
+
20
+ <!-- PWA Manifest -->
21
+ <link rel="manifest" href="/manifest.json" />
22
+
23
+ <!-- Aura typography compatibility -->
24
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
25
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
26
+ <link
27
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&family=Space+Grotesk:wght@300..700&family=Source+Code+Pro:wght@200..900&display=swap"
28
+ rel="stylesheet"
29
+ />
30
+
31
+ </head>
32
+ <body>
33
+ <div id="root"></div>
34
+ <script type="module" src="/src/main.tsx"></script>
35
+ </body>
36
+ </html>
@@ -0,0 +1,67 @@
1
+ ---
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>package.json'
3
+ ---
4
+ {
5
+ "name": "<%= name %>",
6
+ "version": "0.0.0",
7
+ "private": true,
8
+ "type": "module",
9
+ "engines": {
10
+ "node": ">=20",
11
+ "npm": ">=11.10.0"
12
+ },
13
+ "scripts": {
14
+ "start": "vite",
15
+ "dev": "vite",
16
+ "build": "tsc && vite build",
17
+ "preview": "vite preview",
18
+ "test": "vitest run",
19
+ "test:watch": "vitest",
20
+ "test:ui": "vitest --ui",
21
+ "lint": "eslint . --ext .js,.mjs,.cjs,.ts,.tsx",
22
+ "lint:fix": "eslint . --fix --ext .js,.mjs,.cjs,.ts,.tsx",
23
+ "deploy": "npx @cognite/dune@latest deploy:interactive --published",
24
+ "deploy-preview": "npx @cognite/dune@latest deploy:interactive"
25
+ },
26
+ "dependencies": {
27
+ "@cognite/aura": "^0.1.7",
28
+ "@cognite/sdk": "^10.3.0",
29
+ "@cognite/dune": "^3.1.3",
30
+ <% if (infra === 'appsApi') { -%>
31
+ "@cognite/app-sdk": "^0.3.0",
32
+ <% } -%>
33
+ "@tabler/icons-react": "^3.35.0",
34
+ "@tanstack/react-query": "^5.90.10",
35
+ "clsx": "^2.1.1",
36
+ "react": "^18.3.1",
37
+ "react-dom": "^18.3.1",
38
+ "tailwind-merge": "^3.4.0"
39
+ },
40
+ "devDependencies": {
41
+ "@eslint/js": "9.39.4",
42
+ "@tailwindcss/vite": "^4.1.17",
43
+ "@testing-library/jest-dom": "^6.6.3",
44
+ "@testing-library/react": "^16.1.0",
45
+ "@testing-library/user-event": "^14.5.2",
46
+ "@types/node": "^24.10.1",
47
+ "@types/react": "^18.3.1",
48
+ "@types/react-dom": "^18.3.1",
49
+ "@vitejs/plugin-react": "^5.1.1",
50
+ "@vitest/ui": "^2.1.8",
51
+ "autoprefixer": "^10.4.22",
52
+ "eslint": "9.39.4",
53
+ "eslint-plugin-import": "^2.32.0",
54
+ "eslint-plugin-no-only-tests": "^3.3.0",
55
+ "eslint-plugin-react-hooks": "^7.1.1",
56
+ "eslint-plugin-react-refresh": "^0.5.2",
57
+ "globals": "^16.5.0",
58
+ "happy-dom": "^20.9.0",
59
+ "postcss": "^8.5.6",
60
+ "tailwindcss": "^4.1.17",
61
+ "typescript": "^5.0.0",
62
+ "typescript-eslint": "^8.46.4",
63
+ "vite": "^7.2.4",
64
+ "vite-plugin-mkcert": "^1.17.9",
65
+ "vitest": "^2.1.8"
66
+ }
67
+ }
@@ -0,0 +1,45 @@
1
+ ---
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>src/App.test.tsx'
3
+ ---
4
+ import * as appSdk from '@cognite/app-sdk';
5
+ import { render, screen, waitFor } from '@testing-library/react';
6
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
7
+
8
+ import App from './App';
9
+
10
+ vi.mock(import('@cognite/app-sdk'));
11
+
12
+ describe('App', () => {
13
+ beforeEach(() => {
14
+ vi.clearAllMocks();
15
+ });
16
+
17
+ it('renders loading state', () => {
18
+ vi.mocked(appSdk.connectToHostApp).mockReturnValue(new Promise(() => {}));
19
+
20
+ render(<App />);
21
+ expect(screen.getByText('Loading project...')).toBeInTheDocument();
22
+ });
23
+
24
+ it('renders splash with deployment targets and checklist copy', async () => {
25
+ vi.mocked(appSdk.connectToHostApp).mockResolvedValue({
26
+ api: { getProject: vi.fn().mockResolvedValue('my-test-project') } as Partial<appSdk.HostAppAPI> as appSdk.HostAppAPI,
27
+ });
28
+
29
+ render(<App />);
30
+ await waitFor(() => expect(screen.getByText('Welcome to Dune')).toBeInTheDocument());
31
+ expect(screen.getByText('App deployment checklist')).toBeInTheDocument();
32
+ expect(screen.getByText('Plan')).toBeInTheDocument();
33
+ expect(screen.getByText('Explore')).toBeInTheDocument();
34
+ expect(screen.getByText('Deploy')).toBeInTheDocument();
35
+ expect(screen.getByText('Support')).toBeInTheDocument();
36
+ expect(screen.getByText('Help & feedback')).toBeInTheDocument();
37
+ expect(screen.getByText('Your app will deploy to')).toBeInTheDocument();
38
+ expect(screen.getByText('org')).toBeInTheDocument();
39
+ expect(screen.getByText('and project')).toBeInTheDocument();
40
+ expect(screen.getByText('<%= org %>')).toBeInTheDocument();
41
+ expect(screen.getByText('<%= project %>')).toBeInTheDocument();
42
+ expect(screen.getAllByText(/SPEC\.md/).length).toBeGreaterThan(0);
43
+ expect(screen.getByText(/deploy:interactive/)).toBeInTheDocument();
44
+ });
45
+ });