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
21 changes: 5 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,15 @@ on:
branches: [main]

jobs:
lint:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
with:
cache: bun
- run: bun ci
- run: bun run lint

build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
- run: bun run typecheck
- run: bun run compile

test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
- run: xvfb-run -a bun run test:coverage
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
bun run typecheck
bunx lint-staged
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@
"test": "bun run compile && vscode-test",
"test:coverage": "bash scripts/test-coverage.sh",
"test:web": "bun run compile && bunx @vscode/test-web --extensionDevelopmentPath=. --browserType=none",
"typecheck": "tsc --noEmit",
"prepare": "husky"
},
"devDependencies": {
Expand Down
125 changes: 99 additions & 26 deletions src/test/cloud/controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -415,8 +415,8 @@ suite("cloud/cloudController", () => {

await deps.controller.initialize()

// Explicitly wait for status bar update since it's fire-and-forget
await deps.controller["statusBarManager"].update()
// Trigger status bar update via refreshAll
await deps.controller.refreshAll()

assert.strictEqual(deps.statusBar.text, "$(warning) FastAPI Cloud")
assert.ok(warnStub.calledOnce)
Expand Down Expand Up @@ -488,7 +488,8 @@ suite("cloud/cloudController", () => {
newWorkspace,
),
)
assert.strictEqual(deps.controller["workspaceStates"].size, 1)
// Verify state was set by checking that getApp was called (indicates refresh happened)
assert.ok((deps.apiService.getApp as sinon.SinonStub).calledOnce)

dispose(deps)
})
Expand All @@ -515,11 +516,33 @@ suite("cloud/cloudController", () => {
sinon.stub(deps.apiService, "getApp").resolves(testApp)
sinon.stub(deps.apiService, "getTeam").resolves(testTeam)

// Set up active editor to point to workspace
const activeEditor = {
document: { uri: vscode.Uri.file("/tmp/workspace/file.py") },
}
Object.defineProperty(vscode.window, "activeTextEditor", {
value: activeEditor,
configurable: true,
})
sinon
.stub(vscode.workspace, "getWorkspaceFolder")
.returns(workspaceFolder)

await deps.controller.initialize()
assert.strictEqual(deps.controller["workspaceStates"].size, 1)

assert.strictEqual(deps.statusBar.text, "$(cloud) test-app")

deps.controller.removeWorkspaceFolder(workspace)
assert.strictEqual(deps.controller["workspaceStates"].size, 0)

// Verify state was deleted by showing menu - should show setup menu (not_configured)
const quickPickStub = sinon
.stub(vscode.window, "showQuickPick")
.resolves(undefined)
await deps.controller.showMenu()

const items = quickPickStub.firstCall.args[0] as any[]
assert.ok(items.some((i: any) => i.id === "link"))
assert.ok(items.some((i: any) => i.id === "create"))

dispose(deps)
})
Expand Down Expand Up @@ -554,7 +577,11 @@ suite("cloud/cloudController", () => {

await deps.controller.refreshAll()

assert.strictEqual(deps.controller["workspaceStates"].size, 2)
// Verify both workspaces were refreshed by checking getApp was called twice
assert.strictEqual(
(deps.apiService.getApp as sinon.SinonStub).callCount,
2,
)

dispose(deps)
})
Expand Down Expand Up @@ -609,15 +636,29 @@ suite("cloud/cloudController", () => {
configurable: true,
})

const activeEditor = {
document: { uri: vscode.Uri.file("/tmp/workspace/file.py") },
}
Object.defineProperty(vscode.window, "activeTextEditor", {
value: activeEditor,
configurable: true,
})
sinon
.stub(vscode.workspace, "getWorkspaceFolder")
.returns(workspaceFolder)

sinon
.stub(vscode.authentication, "getSession")
.rejects(new Error("Auth error"))
sinon.stub(deps.configService, "startWatching")

await deps.controller.initialize()

const state = deps.controller["getState"](workspace)
assert.strictEqual(state.status, "not_configured")
// Verify state is not_configured by checking status bar shows sign-in
assert.strictEqual(
deps.statusBar.text,
"$(cloud) Sign into FastAPI Cloud",
)

dispose(deps)
})
Expand All @@ -632,6 +673,17 @@ suite("cloud/cloudController", () => {
configurable: true,
})

const activeEditor = {
document: { uri: vscode.Uri.file("/tmp/workspace/file.py") },
}
Object.defineProperty(vscode.window, "activeTextEditor", {
value: activeEditor,
configurable: true,
})
sinon
.stub(vscode.workspace, "getWorkspaceFolder")
.returns(workspaceFolder)

sinon
.stub(vscode.authentication, "getSession")
.resolves(mockSession as any)
Expand All @@ -642,8 +694,8 @@ suite("cloud/cloudController", () => {

await deps.controller.initialize()

const state = deps.controller["getState"](workspace)
assert.strictEqual(state.status, "error")
// Verify state is error by checking status bar shows setup (error state shows setup)
assert.strictEqual(deps.statusBar.text, "$(cloud) Set up FastAPI Cloud")

dispose(deps)
})
Expand Down Expand Up @@ -679,13 +731,7 @@ suite("cloud/cloudController", () => {
await deps.controller.initialize()
assert.strictEqual(warnStub.callCount, 1)

// Manually mark warning as shown
deps.controller["setState"](workspace, {
status: "not_found",
warningShown: true,
})

// Second refresh - should NOT show warning again
// Second refresh - warning was dismissed (resolved undefined), so should NOT show again
await deps.controller.refresh(workspace)
assert.strictEqual(warnStub.callCount, 1) // Still 1, not 2

Expand Down Expand Up @@ -753,6 +799,17 @@ suite("cloud/cloudController", () => {
configurable: true,
})

const activeEditor = {
document: { uri: vscode.Uri.file("/tmp/workspace/file.py") },
}
Object.defineProperty(vscode.window, "activeTextEditor", {
value: activeEditor,
configurable: true,
})
sinon
.stub(vscode.workspace, "getWorkspaceFolder")
.returns(workspaceFolder)

sinon
.stub(vscode.authentication, "getSession")
.resolves(mockSession as any)
Expand All @@ -772,8 +829,8 @@ suite("cloud/cloudController", () => {

await deps.controller.createAndLinkProject(workspace)

const state = deps.controller["getState"](workspace)
assert.strictEqual(state.status, "linked")
// Verify state is linked by checking status bar shows app slug
assert.strictEqual(deps.statusBar.text, "$(cloud) test-app")

dispose(deps)
})
Expand Down Expand Up @@ -859,7 +916,7 @@ suite("cloud/cloudController", () => {
.withArgs(editor1.document.uri)
.returns(workspaceFolder1)

await deps.controller["statusBarManager"].update()
await deps.controller.refreshAll()
assert.strictEqual(deps.statusBar.text, "$(cloud) test-app")

// Switch to workspace2 file
Expand All @@ -874,7 +931,7 @@ suite("cloud/cloudController", () => {
.withArgs(editor2.document.uri)
.returns(workspaceFolder2)

await deps.controller["statusBarManager"].update()
await deps.controller.refreshAll()
assert.strictEqual(deps.statusBar.text, "$(cloud) test-app-2")

dispose(deps)
Expand Down Expand Up @@ -925,7 +982,7 @@ suite("cloud/cloudController", () => {
.withArgs(editor1.document.uri)
.returns(workspaceFolder1)

await deps.controller["statusBarManager"].update()
await deps.controller.refreshAll()
assert.strictEqual(deps.statusBar.text, "$(cloud) test-app")

// workspace2 file shows setup
Expand All @@ -940,7 +997,7 @@ suite("cloud/cloudController", () => {
.withArgs(editor2.document.uri)
.returns(workspaceFolder2)

await deps.controller["statusBarManager"].update()
await deps.controller.refreshAll()
assert.strictEqual(deps.statusBar.text, "$(cloud) Set up FastAPI Cloud")

dispose(deps)
Expand Down Expand Up @@ -1166,6 +1223,18 @@ suite("cloud/cloudController", () => {
configurable: true,
})

// Set up active editor
const editor1 = {
document: { uri: vscode.Uri.file("/tmp/workspace1/file.py") },
}
Object.defineProperty(vscode.window, "activeTextEditor", {
value: editor1,
configurable: true,
})
sinon
.stub(vscode.workspace, "getWorkspaceFolder")
.returns(workspaceFolder1)

const getSessionStub = sinon.stub(vscode.authentication, "getSession")
getSessionStub.resolves(mockSession as any)

Expand All @@ -1178,7 +1247,8 @@ suite("cloud/cloudController", () => {

await deps.controller.initialize()

assert.strictEqual(deps.controller["workspaceStates"].size, 2)
// Verify workspaces are linked by checking status bar shows app
assert.strictEqual(deps.statusBar.text, "$(cloud) test-app")

sinon
.stub(vscode.window, "showWarningMessage")
Expand All @@ -1190,8 +1260,11 @@ suite("cloud/cloudController", () => {

await deps.controller.signOut()

// All workspace states should be cleared
assert.strictEqual(deps.controller["workspaceStates"].size, 0)
// All workspace states should be cleared - status bar shows sign-in
assert.strictEqual(
deps.statusBar.text,
"$(cloud) Sign into FastAPI Cloud",
)

dispose(deps)
})
Expand Down
Loading