Skip to content
Merged
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/cli/.prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
dist/
node_modules/
.claude/
CHANGELOG.md
1 change: 1 addition & 0 deletions packages/core/.prettierignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
dist/
node_modules/
CHANGELOG.md
7 changes: 4 additions & 3 deletions packages/core/__tests__/integrations/mcp-disconnect.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import {
createProjectDir,
isolateHome,
writeClaudeSettings,
writeCodexConfig,
writeCursorMcpConfig,
Expand Down Expand Up @@ -90,7 +91,7 @@ describe('cursor disconnectMcpServer', () => {
it('removes the server from global config and CLI permissions', async () => {
using project = createProjectDir('empty');
using home = createProjectDir('empty');
vi.stubEnv('HOME', home.path);
using _home = isolateHome(home.path);
writeCursorMcpConfig(home.path, {
mcpServers: {
'confidence-flags': { type: 'http', url: 'https://example.com' },
Expand Down Expand Up @@ -131,7 +132,7 @@ describe('codex disconnectMcpServer', () => {

it('removes the server section from project and global configs', async () => {
using project = createProjectDir('empty');
vi.stubEnv('HOME', project.path);
using _home = isolateHome(project.path);
const toml = [
'[mcp_servers.confidence-flags]',
'url = "https://example.com"',
Expand All @@ -152,7 +153,7 @@ describe('codex disconnectMcpServer', () => {

it('does not fail when config files do not exist', async () => {
using project = createProjectDir('empty');
vi.stubEnv('HOME', project.path);
using _home = isolateHome(project.path);
const sut = await loadDisconnect();

await expect(
Expand Down
1 change: 1 addition & 0 deletions packages/quickstart/.prettierignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
dist/
node_modules/
CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
act,
renderScreen,
createProjectDir,
isolateHome,
prepareAuthTokens,
waitFor,
buildExpiredJwt,
Expand Down Expand Up @@ -37,9 +38,10 @@ describe('ConnectToolsScreen', () => {
http.post('https://mcp.confidence.dev/mcp/docs', () => HttpResponse.error()),
);

using project = createProjectDir();
using _home = isolateHome(project.path);
using _auth = prepareAuthTokens('none');
using _pref = createMcpPreference('connected');
using project = createProjectDir();

// Act
using sut = renderScreen(<ConnectToolsScreen />, {
Expand Down Expand Up @@ -175,8 +177,9 @@ describe('ConnectToolsScreen', () => {
),
);

using _auth = prepareAuthTokens('none');
using project = createProjectDir();
using _home = isolateHome(project.path);
using _auth = prepareAuthTokens('none');

using sut = renderScreen(<ConnectToolsScreen />, {
screen: ScreenId.ConnectTools,
Expand All @@ -203,7 +206,7 @@ type SeedMcpOpts = {
};

function seedMcpRegistration(projectDir: string, opts?: SeedMcpOpts) {
vi.stubEnv('HOME', projectDir);
const home = isolateHome(projectDir);

const headers = opts?.token ? { Authorization: `Bearer ${opts.token}` } : undefined;
const servers = {
Expand All @@ -223,7 +226,7 @@ function seedMcpRegistration(projectDir: string, opts?: SeedMcpOpts) {

return {
[Symbol.dispose]() {
vi.unstubAllEnvs();
home[Symbol.dispose]();
},
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
renderScreen,
renderApp,
createProjectDir,
isolateHome,
prepareAuthTokens,
ENTER,
ARROW_DOWN,
Expand All @@ -20,8 +21,9 @@ vi.mock('../../../../core/src/exec/exec.js', () => ({

describe('ConnectToolsScreen', () => {
it('renders title', async () => {
using _auth = prepareAuthTokens('none');
using project = createProjectDir();
using _home = isolateHome(project.path);
using _auth = prepareAuthTokens('none');
using sut = renderScreen(<ConnectToolsScreen />, {
screen: ScreenId.ConnectTools,
dir: project.path,
Expand All @@ -32,8 +34,9 @@ describe('ConnectToolsScreen', () => {
});

it('shows tool list after detection', async () => {
using _auth = prepareAuthTokens('none');
using project = createProjectDir();
using _home = isolateHome(project.path);
using _auth = prepareAuthTokens('none');
using sut = renderScreen(<ConnectToolsScreen />, {
screen: ScreenId.ConnectTools,
dir: project.path,
Expand All @@ -45,8 +48,9 @@ describe('ConnectToolsScreen', () => {
});

it('shows connect options', async () => {
using _auth = prepareAuthTokens('none');
using project = createProjectDir();
using _home = isolateHome(project.path);
using _auth = prepareAuthTokens('none');
using sut = renderScreen(<ConnectToolsScreen />, {
screen: ScreenId.ConnectTools,
dir: project.path,
Expand All @@ -58,8 +62,9 @@ describe('ConnectToolsScreen', () => {

describe('when connection succeeds', () => {
it('connects and shows success message', async () => {
using _auth = prepareAuthTokens('none');
using project = createProjectDir();
using _home = isolateHome(project.path);
using _auth = prepareAuthTokens('none');
using sut = renderScreen(<ConnectToolsScreen />, {
screen: ScreenId.ConnectTools,
dir: project.path,
Expand All @@ -84,8 +89,9 @@ describe('ConnectToolsScreen', () => {
http.post('https://mcp.confidence.dev/mcp/docs', () => HttpResponse.error()),
);

using _auth = prepareAuthTokens('none');
using project = createProjectDir();
using _home = isolateHome(project.path);
using _auth = prepareAuthTokens('none');
using sut = renderScreen(<ConnectToolsScreen />, {
screen: ScreenId.ConnectTools,
dir: project.path,
Expand All @@ -105,8 +111,9 @@ describe('ConnectToolsScreen', () => {
it('shows partial failure status', async () => {
server.use(http.post('https://mcp.confidence.dev/mcp/docs', () => HttpResponse.error()));

using _auth = prepareAuthTokens('none');
using project = createProjectDir();
using _home = isolateHome(project.path);
using _auth = prepareAuthTokens('none');
using sut = renderScreen(<ConnectToolsScreen />, {
screen: ScreenId.ConnectTools,
dir: project.path,
Expand All @@ -127,8 +134,9 @@ describe('ConnectToolsScreen', () => {

describe('when user skips', () => {
it('shows skip confirmation and auto-advances', async () => {
using _auth = prepareAuthTokens('none');
using project = createProjectDir();
using _home = isolateHome(project.path);
using _auth = prepareAuthTokens('none');
using sut = renderApp({ screen: ScreenId.ConnectTools, dir: project.path });

await waitFor(() => {
Expand Down
6 changes: 5 additions & 1 deletion packages/quickstart/__tests__/ui/testing-framework/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ export {
buildAuthState,
prepareAuthTokens,
} from '@spotify-confidence/testing/auth';
export { createProjectDir, type ProjectType } from '@spotify-confidence/testing/scaffold';
export {
createProjectDir,
isolateHome,
type ProjectType,
} from '@spotify-confidence/testing/scaffold';
export {
KEY_MAP,
resolveKey,
Expand Down
22 changes: 22 additions & 0 deletions packages/testing/src/scaffold/home-scaffold.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { vi } from 'vitest';

/**
* Stubs the `HOME` environment variable to `dir`, isolating the test
* from real user config files (`~/.cursor/`, `~/.claude.json`, etc.).
* Supports `Symbol.dispose` for automatic cleanup via `vi.unstubAllEnvs`.
*
* @example
* ```ts
* using project = createProjectDir();
* using _home = isolateHome(project.path);
* ```
*/
export function isolateHome(dir: string) {
vi.stubEnv('HOME', dir);

return {
[Symbol.dispose]() {
vi.unstubAllEnvs();
},
};
}
1 change: 1 addition & 0 deletions packages/testing/src/scaffold/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { createConfigDir } from './config-scaffold.js';
export { isolateHome } from './home-scaffold.js';
export { createProjectDir } from './project-scaffold.js';
export {
writeClaudeSettings,
Expand Down
Loading