Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
10 changes: 5 additions & 5 deletions web/.agents/skills/test-coverage-improvement/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Combine **`coverage-final.json`** with judgment—**do not** use only the bottom
- Sort by low **`lines.pct`** / **`statements.pct`** among included source files.
- **Prefer:** logic-heavy modules, hooks, API glue, non-trivial components, error paths.
- **Skip or defer:** thin re-exports, empty barrels, generated-only files, trivial constants (unless user asked otherwise).
- **Exclude:** `*.spec.*`, `*.test.*`, `e2e-tests/**`, `node_modules/**`, outside **`coverage.include`**.
- **Exclude:** `*.test.*`, `e2e-tests/**`, `node_modules/**`, outside **`coverage.include`**.

Output a **numbered list** (path, %, one-line rationale). **Do not wait for approval** unless the user explicitly asked to confirm the list; proceed to the loop.

Expand All @@ -73,15 +73,15 @@ If the file is **untestable without refactor**, add a **short skip note** in the

- **React:** **`web/.agents/skills/unit-test/SKILL.md`** (RTL, MSW, `findBy*`, `vi.mock`).
- **Non-React:** Vitest + **`vi.mock`** as needed.
- Colocate **`*.spec.ts` / `*.spec.tsx`** unless the package uses another established pattern.
- Colocate **`*.test.ts` / `*.test.tsx`** unless the package uses another established pattern.

### 3d. Verify before next file

1. `pnpm vitest --run path/to/File.spec.ts` (and any related specs) until **exit 0**.
1. `pnpm vitest --run path/to/File.test.ts` (and any related specs) until **exit 0**.
2. **`pnpm typecheck`**; **`pnpm typecheck:go`** if defined. Fix TypeScript issues (TanStack context, SDK types, etc.).
3. Optionally re-run coverage for the package and note improvement for that file.

Keep a **running list** of every file path you **create or edit** during §3 (new **`*.spec.*`**, and any production files you touch). You will pass that list to eslint in §4.
Keep a **running list** of every file path you **create or edit** during §3 (new **`*.test.*`**, and any production files you touch). You will pass that list to eslint in §4.

You may fix obvious **ESLint** issues (e.g. **`import/order`**) during §3d when **`typecheck`** is already clean.

Expand All @@ -92,7 +92,7 @@ When **all** shortlist iterations in §3 are finished (not after each file):
1. `cd web/packages/<target>`.
2. From **`package.json`**, read the **`lint`** script and reuse the **same eslint flags** as the project (everything after the `eslint` command—e.g. **`--report-unused-disable-directives --max-warnings 0`** for Studio), but **replace the path glob** (e.g. `.`) with **only your tracked file paths**:
```bash
pnpm exec eslint --report-unused-disable-directives --max-warnings 0 path/to/A.spec.ts path/to/B.spec.ts
pnpm exec eslint --report-unused-disable-directives --max-warnings 0 path/to/A.test.ts path/to/B.test.ts
```
3. If the package uses **`lint:fix`** for local workflow, you may run **`pnpm exec eslint --fix ...`** with the **same file list** first, then re-run without **`--fix`** if needed to confirm **exit 0**.
4. Fix any reported issues until eslint exits **0** on that list.
Expand Down
4 changes: 2 additions & 2 deletions web/.agents/skills/unit-test/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,14 @@ Two acceptable patterns from `web/`:
```bash
# Pattern A — filter from web/ root
pnpm --filter nemo-studio-ui test # whole package
pnpm --filter nemo-studio-ui test -- src/components/Button.spec.tsx # specific file
pnpm --filter nemo-studio-ui test -- src/components/Button.test.tsx # specific file
pnpm --filter nemo-studio-ui test -- --reporter=verbose Button # pattern match
pnpm --filter nemo-studio-ui test -- --coverage # with coverage

# Pattern B — cd into the package
cd packages/studio
pnpm test # whole package
pnpm test -- src/components/Button.spec.tsx # specific file
pnpm test -- src/components/Button.test.tsx # specific file
```

`pnpm test` already passes `--run` (no watch mode) — tests run to completion so results can be read and iterated on.
Expand Down
2 changes: 1 addition & 1 deletion web/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Cursor/Claude skills for this monorepo live under **`web/.agents/skills/`** (for
- **Never invoke `vitest` directly** (e.g. `pnpm vitest --run`). Always go through a package's `test` script so env/config (e.g. `NODE_OPTIONS=--max-old-space-size=10240` in `studio`) is applied.
- Use one of these patterns from `web/`:
- Whole package: `pnpm --filter <package-name> test` (e.g. `pnpm --filter nemo-studio-ui test`, `pnpm --filter @nemo/common test`)
- Targeted file: `pnpm --filter <package-name> test path/to/file.spec.tsx`
- Targeted file: `pnpm --filter <package-name> test path/to/file.test.tsx`

## CI Scripts Convention

Expand Down
4 changes: 2 additions & 2 deletions web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ Stack: [Vitest](https://vitest.dev/) + [React Testing Library](https://testing-l

Conventions:

- Co-locate unit tests next to source: `Chat/index.tsx` ↔ `Chat/index.spec.tsx`.
- Larger user-workflow tests (create/delete project, chat, etc.) live in `packages/studio/src/tests`, e.g. `create-a-model.spec.tsx`.
- Co-locate unit tests next to source: `Chat/index.tsx` ↔ `Chat/index.test.tsx`.
- Larger user-workflow tests (create/delete project, chat, etc.) live in `packages/studio/src/tests`, e.g. `create-a-model.test.tsx`.
- E2E specs live in `packages/studio/e2e-tests`.

From `/packages/studio`:
Expand Down
31 changes: 31 additions & 0 deletions web/eslint-plugins/test-naming.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

/** @type {import('eslint').Rule.RuleModule} */
const noSpecSuffix = {
meta: {
type: 'suggestion',
docs: { description: 'Enforce .test. suffix; disallow .spec.' },
},
create(context) {
const filename = context.filename ?? context.getFilename?.();
if (/\.spec\.[jt]sx?$/.test(filename)) {
return {
Program(node) {
context.report({
node,
message: 'Use .test. suffix instead of .spec. (rename to *.test.ts / *.test.tsx).',
});
},
};
}
return {};
},
};

/** @type {import('eslint').ESLint.Plugin} */
export default {
rules: {
'no-spec-suffix': noSpecSuffix,
},
};
8 changes: 7 additions & 1 deletion web/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import noOnlyTestsPlugin from 'eslint-plugin-no-only-tests';
import testingLibrary from 'eslint-plugin-testing-library';
import vitest from '@vitest/eslint-plugin';
import tseslint from 'typescript-eslint';
import testNamingPlugin from './eslint-plugins/test-naming.js';

const pathPrefix = '';

Expand Down Expand Up @@ -175,8 +176,13 @@ export default [
// Handles tests
{
files: [`${pathPrefix}**/src/**/*.{test,spec}.{js,jsx,ts,tsx}`],
plugins: { vitest, ...testingLibrary.configs['flat/react'].plugins },
plugins: {
vitest,
...testingLibrary.configs['flat/react'].plugins,
'test-naming': testNamingPlugin,
},
rules: {
'test-naming/no-spec-suffix': 'error',
...testingLibrary.configs['flat/react'].rules,
'vitest/consistent-test-it': ['error', { fn: 'it' }],
'testing-library/no-debugging-utils': 'error',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import { getLanguageFromFilePath, isCodeSnippetLanguage, languageInCode } from './codeSnippet';
import {
getLanguageFromFilePath,
isCodeSnippetLanguage,
languageInCode,
} from '@nemo/common/src/utils/codeSnippet';

describe('isCodeSnippetLanguage', () => {
it('returns true for supported languages', () => {
Expand Down
45 changes: 0 additions & 45 deletions web/packages/common/src/utils/search.spec.ts

This file was deleted.

6 changes: 5 additions & 1 deletion web/packages/common/src/utils/search.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

import { buildApiSearchParam, convertQueryToList, mergeURLSearchParams } from './search';
import {
buildApiSearchParam,
convertQueryToList,
mergeURLSearchParams,
} from '@nemo/common/src/utils/search';

describe('buildApiSearchParam', () => {
it('returns undefined for undefined input', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const test = baseTest.extend<TestFixtures>({
},
testProject: async ({ request }, runFixture) => {
const projectDisplayName = generateTestResourceName('project');
const projectDescription = `Project created by customization.spec.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
const projectDescription = `Project created by customization.test.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
await testProjectFixture(
request,
runFixture,
Expand All @@ -72,7 +72,7 @@ const test = baseTest.extend<TestFixtures>({
},
testDataset: async ({ request, testProject }, runFixture) => {
const datasetName = generateShortTestResourceName();
const datasetDescription = `Dataset created by customization.spec.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
const datasetDescription = `Dataset created by customization.test.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
await testDatasetFixture(
request,
runFixture,
Expand All @@ -95,7 +95,7 @@ const test = baseTest.extend<TestFixtures>({
]);
},
testCustomizationJob: async ({ request, testCustomizationFiles }, runFixture) => {
const jobDescription = `Customization job created by customization.spec.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
const jobDescription = `Customization job created by customization.test.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
const requestBody: CustomizationJobRequest = {
description: jobDescription,
project: `${testCustomizationFiles.project.workspace}/${testCustomizationFiles.project.name}`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ const test = baseTest.extend<TestFixtures>({
},
testProject: async ({ request }, runFixture) => {
const projectDisplayName = generateTestResourceName('project');
const projectDescription = `Project created by evaluation.spec.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
const projectDescription = `Project created by evaluation.test.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
Comment thread
steramae-nvidia marked this conversation as resolved.
await testProjectFixture(
request,
runFixture,
Expand All @@ -184,7 +184,7 @@ const test = baseTest.extend<TestFixtures>({
},
testDataset: async ({ request, testProject }, runFixture) => {
const datasetName = generateTestResourceName('dataset');
const datasetDescription = `Dataset created by evaluation.spec.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
const datasetDescription = `Dataset created by evaluation.test.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
await testDatasetFixture(
request,
runFixture,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const test = baseTest.extend<TestFixtures>({
},
testProject: async ({ request }, runFixture) => {
const projectDisplayName = generateTestResourceName('project');
const projectDescription = `Project created by datasets.spec.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
const projectDescription = `Project created by datasets.test.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
await testProjectFixture(
request,
runFixture,
Expand All @@ -57,7 +57,7 @@ const test = baseTest.extend<TestFixtures>({
},
testDataset: async ({ request, testProject }, runFixture) => {
const datasetName = generateTestResourceName('dataset');
const datasetDescription = `Dataset created by datasets.spec.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
const datasetDescription = `Dataset created by datasets.test.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
await testDatasetFixture(
request,
runFixture,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const test = baseTest.extend<TestFixtures>({
},
testProject: async ({ request }, runFixture) => {
const projectDisplayName = generateTestResourceName('project');
const projectDescription = `Project created by model-inference.spec.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
const projectDescription = `Project created by model-inference.test.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
await testProjectFixture(
request,
runFixture,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const test = baseTest.extend<TestFixtures>({
},
testProject: async ({ request }, runFixture) => {
const projectDisplayName = generateTestResourceName('project');
const projectDescription = `Project created by model.spec.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
const projectDescription = `Project created by model.test.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
await testProjectFixture(
request,
runFixture,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const test = baseTest.extend<TestFixtures>({
},
testProject: async ({ request }, runFixture) => {
const projectDisplayName = generateTestResourceName('project');
const projectDescription = `Project created by project.spec.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
const projectDescription = `Project created by project.test.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
await testProjectFixture(
request,
runFixture,
Expand All @@ -59,7 +59,7 @@ test.describe('Projects', () => {
test('Creates a project', async ({ page, projectsPage, projectsApi }) => {
test.slow();
const projectDisplayName = generateTestResourceName('project');
const projectDescription = `Project created by project.spec.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
const projectDescription = `Project created by project.test.ts E2E test on ${CURRENT_YYYY_MM_DD}`;

await projectsPage.goto();
await projectsPage.waitForPageLoad();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const test = baseTest.extend<TestFixtures>({
},
testProject: async ({ request }, runFixture) => {
const projectDisplayName = generateTestResourceName('project');
const projectDescription = `Project created by SafeSynthesizer.spec.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
const projectDescription = `Project created by SafeSynthesizer.test.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
await testProjectFixture(
request,
runFixture,
Expand All @@ -55,7 +55,7 @@ const test = baseTest.extend<TestFixtures>({
},
testDataset: async ({ request, testProject }, runFixture) => {
const datasetName = generateShortTestResourceName();
const datasetDescription = `Dataset created by safeSynthesizer.spec.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
const datasetDescription = `Dataset created by safeSynthesizer.test.ts E2E test on ${CURRENT_YYYY_MM_DD}`;
await testDatasetFixture(
request,
runFixture,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ describe('SafeSynthesizerFilesetPreview', () => {
});

// Note: Data Source Preview functionality is now handled by FilesetFilePreviewLink
// which is tested separately in FilesetFilePreviewLink.spec.tsx
// which is tested separately in FilesetFilePreviewLink.test.tsx
describe('Data Source Preview', () => {
it('should render FilesetFilePreviewLink for data source', () => {
const job = createMockJob();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

// utils.test.ts
import { ContentType } from '@nemo/common/src/components/CodeEditor/constants';
import {
collectFolderPathsFromDatasetFiles,
Expand Down
Loading
Loading