feat: publish HoloLake model-native living system source
This commit is contained in:
parent
6ad10edde1
commit
c395dd3a99
2467 changed files with 615073 additions and 0 deletions
|
|
@ -0,0 +1,253 @@
|
|||
import { expect, test, type Page } from '@playwright/test'
|
||||
import { executeCommand, openCommandPalette } from './helpers'
|
||||
import { seedAutoGitSavedChange } from './testBridge'
|
||||
|
||||
type MockHandler = (args?: Record<string, unknown>) => unknown
|
||||
|
||||
function installAutoGitMocks() {
|
||||
type BrowserWindow = Window & typeof globalThis & {
|
||||
__getDirtyPathCount?: () => number
|
||||
__gitCommitAttempts?: number
|
||||
__gitCommitMessages?: string[]
|
||||
__gitPushCalls?: number
|
||||
__mockHandlers?: Record<string, MockHandler>
|
||||
__setMockAppActive?: (active: boolean) => void
|
||||
__setMockGitCommitFailure?: (message: string | null) => void
|
||||
}
|
||||
|
||||
const browserWindow = window as BrowserWindow
|
||||
const dirtyPaths = new Set<string>()
|
||||
let appActive = true
|
||||
let ahead = 0
|
||||
let gitCommitFailure: string | null = null
|
||||
|
||||
const createModifiedFiles = () => [...dirtyPaths].map((path) => ({
|
||||
path,
|
||||
relativePath: path.split('/').pop() ?? path,
|
||||
status: 'modified',
|
||||
}))
|
||||
|
||||
const isPatched = (handlers?: Record<string, MockHandler> | null) =>
|
||||
!handlers || (handlers as Record<string, unknown>).__autogitPatched === true
|
||||
|
||||
const patchSaveNoteContent = (handlers: Record<string, MockHandler>) => {
|
||||
const originalSaveNoteContent = handlers.save_note_content
|
||||
handlers.save_note_content = (args?: Record<string, unknown>) => {
|
||||
const path = typeof args?.path === 'string' ? args.path : null
|
||||
if (path) dirtyPaths.add(path)
|
||||
return originalSaveNoteContent?.(args)
|
||||
}
|
||||
}
|
||||
|
||||
const patchGitHandlers = (handlers: Record<string, MockHandler>) => {
|
||||
handlers.get_modified_files = () => createModifiedFiles()
|
||||
|
||||
handlers.git_commit = (args?: Record<string, unknown>) => {
|
||||
browserWindow.__gitCommitAttempts = (browserWindow.__gitCommitAttempts ?? 0) + 1
|
||||
if (gitCommitFailure) {
|
||||
throw new Error(gitCommitFailure)
|
||||
}
|
||||
|
||||
const message = typeof args?.message === 'string' ? args.message : ''
|
||||
browserWindow.__gitCommitMessages?.push(message)
|
||||
dirtyPaths.clear()
|
||||
ahead = 1
|
||||
return `[main abc1234] ${message}`
|
||||
}
|
||||
|
||||
handlers.git_push = () => {
|
||||
browserWindow.__gitPushCalls = (browserWindow.__gitPushCalls ?? 0) + 1
|
||||
ahead = 0
|
||||
return { status: 'ok', message: 'Pushed to remote' }
|
||||
}
|
||||
|
||||
handlers.git_remote_status = () => ({
|
||||
branch: 'main',
|
||||
ahead,
|
||||
behind: 0,
|
||||
hasRemote: true,
|
||||
})
|
||||
}
|
||||
|
||||
const markPatched = (handlers: Record<string, MockHandler>) => {
|
||||
Object.defineProperty(handlers, '__autogitPatched', {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
value: true,
|
||||
})
|
||||
}
|
||||
|
||||
const patchHandlers = (handlers?: Record<string, MockHandler> | null) => {
|
||||
if (isPatched(handlers)) {
|
||||
return handlers ?? null
|
||||
}
|
||||
|
||||
patchSaveNoteContent(handlers)
|
||||
patchGitHandlers(handlers)
|
||||
markPatched(handlers)
|
||||
return handlers
|
||||
}
|
||||
|
||||
document.hasFocus = () => appActive
|
||||
browserWindow.__setMockAppActive = (active: boolean) => {
|
||||
appActive = active
|
||||
}
|
||||
browserWindow.__setMockGitCommitFailure = (message: string | null) => {
|
||||
gitCommitFailure = message
|
||||
}
|
||||
browserWindow.__getDirtyPathCount = () => dirtyPaths.size
|
||||
browserWindow.__gitCommitAttempts = 0
|
||||
browserWindow.__gitCommitMessages = []
|
||||
browserWindow.__gitPushCalls = 0
|
||||
|
||||
let ref = patchHandlers(browserWindow.__mockHandlers) ?? null
|
||||
Object.defineProperty(browserWindow, '__mockHandlers', {
|
||||
configurable: true,
|
||||
get() {
|
||||
return patchHandlers(ref) ?? ref
|
||||
},
|
||||
set(value) {
|
||||
ref = patchHandlers(value as Record<string, MockHandler> | undefined) ?? null
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
async function openFirstNote(page: Page) {
|
||||
const noteList = page.locator('[data-testid="note-list-container"]')
|
||||
await noteList.waitFor({ timeout: 5_000 })
|
||||
await noteList.locator('.cursor-pointer').first().click()
|
||||
await expect(page.locator('.bn-editor')).toBeVisible({ timeout: 5_000 })
|
||||
}
|
||||
|
||||
async function openAutoGitSettings(page: Page) {
|
||||
await openCommandPalette(page)
|
||||
await executeCommand(page, 'Open Settings')
|
||||
|
||||
const settingsPanel = page.getByTestId('settings-panel')
|
||||
await expect(settingsPanel).toBeVisible({ timeout: 5_000 })
|
||||
|
||||
const autoGitSwitch = settingsPanel.getByRole('switch', { name: 'AutoGit' })
|
||||
await expect(autoGitSwitch).toBeEnabled({ timeout: 5_000 })
|
||||
await autoGitSwitch.click({ force: true })
|
||||
await page.getByTestId('settings-autogit-idle-threshold').fill('2')
|
||||
await page.getByTestId('settings-autogit-inactive-threshold').fill('2')
|
||||
await page.getByTestId('settings-save').click()
|
||||
await expect(settingsPanel).not.toBeVisible({ timeout: 5_000 })
|
||||
}
|
||||
|
||||
async function expectDirtyPathCount(page: Page, expectedCount: number) {
|
||||
await expect.poll(async () =>
|
||||
page.evaluate(() => (window as Window & { __getDirtyPathCount?: () => number }).__getDirtyPathCount?.() ?? 0),
|
||||
).toBe(expectedCount)
|
||||
}
|
||||
|
||||
async function expectCommitMessageCount(page: Page, expectedCount: number) {
|
||||
await expect.poll(async () =>
|
||||
page.evaluate(() => (window as Window & { __gitCommitMessages?: string[] }).__gitCommitMessages?.length ?? 0),
|
||||
).toBe(expectedCount)
|
||||
}
|
||||
|
||||
async function expectCommitAttemptCount(page: Page, expectedCount: number) {
|
||||
await expect.poll(async () =>
|
||||
page.evaluate(() => (window as Window & { __gitCommitAttempts?: number }).__gitCommitAttempts ?? 0),
|
||||
).toBe(expectedCount)
|
||||
}
|
||||
|
||||
async function expectCommitMessage(page: Page, index: number, expectedMessage: string) {
|
||||
await expect.poll(async () =>
|
||||
page.evaluate(
|
||||
({ targetIndex }) => (window as Window & { __gitCommitMessages?: string[] }).__gitCommitMessages?.[targetIndex] ?? '',
|
||||
{ targetIndex: index },
|
||||
),
|
||||
).toBe(expectedMessage)
|
||||
}
|
||||
|
||||
async function expectPushCount(page: Page, expectedCount: number) {
|
||||
await expect.poll(async () =>
|
||||
page.evaluate(() => (window as Window & { __gitPushCalls?: number }).__gitPushCalls ?? 0),
|
||||
).toBe(expectedCount)
|
||||
}
|
||||
|
||||
async function expectCheckpoint(page: Page, count: number) {
|
||||
await expectCommitMessageCount(page, count)
|
||||
await expectCommitMessage(page, count - 1, 'Updated 1 note')
|
||||
await expectPushCount(page, count)
|
||||
}
|
||||
|
||||
async function seedSavedChange(page: Page) {
|
||||
await seedAutoGitSavedChange(page)
|
||||
await expectDirtyPathCount(page, 1)
|
||||
}
|
||||
|
||||
async function setMockAppActive(page: Page, active: boolean) {
|
||||
await page.evaluate((nextActive) => {
|
||||
;(window as Window & { __setMockAppActive?: (active: boolean) => void }).__setMockAppActive?.(nextActive)
|
||||
window.dispatchEvent(new Event(nextActive ? 'focus' : 'blur'))
|
||||
}, active)
|
||||
}
|
||||
|
||||
async function setMockGitCommitFailure(page: Page, message: string | null) {
|
||||
await page.evaluate((failureMessage) => {
|
||||
;(window as Window & {
|
||||
__setMockGitCommitFailure?: (message: string | null) => void
|
||||
}).__setMockGitCommitFailure?.(failureMessage)
|
||||
}, message)
|
||||
}
|
||||
|
||||
async function triggerQuickCommit(page: Page) {
|
||||
const commitButton = page.getByTestId('status-commit-push')
|
||||
await expect(commitButton).toBeEnabled({ timeout: 5_000 })
|
||||
await commitButton.click()
|
||||
}
|
||||
|
||||
test('@smoke AutoGit checkpoints on idle, and the bottom bar reuses the same message', async ({ page }) => {
|
||||
await page.addInitScript(installAutoGitMocks)
|
||||
await page.goto('/')
|
||||
await page.waitForLoadState('networkidle')
|
||||
|
||||
await openAutoGitSettings(page)
|
||||
await openFirstNote(page)
|
||||
|
||||
await seedSavedChange(page)
|
||||
await expectCheckpoint(page, 1)
|
||||
|
||||
await seedSavedChange(page)
|
||||
await triggerQuickCommit(page)
|
||||
await expectCheckpoint(page, 2)
|
||||
|
||||
await expect(page.locator('.fixed.bottom-8')).toContainText('Committed and pushed', { timeout: 5_000 })
|
||||
})
|
||||
|
||||
test('AutoGit checkpoints when the app is inactive', async ({ page }) => {
|
||||
await page.addInitScript(installAutoGitMocks)
|
||||
await page.goto('/')
|
||||
await page.waitForLoadState('networkidle')
|
||||
|
||||
await openAutoGitSettings(page)
|
||||
await openFirstNote(page)
|
||||
await setMockAppActive(page, false)
|
||||
|
||||
await seedSavedChange(page)
|
||||
await expectCheckpoint(page, 1)
|
||||
})
|
||||
|
||||
test('AutoGit does not retry a failed checkpoint until the next saved change', async ({ page }) => {
|
||||
await page.addInitScript(installAutoGitMocks)
|
||||
await page.goto('/')
|
||||
await page.waitForLoadState('networkidle')
|
||||
|
||||
await openAutoGitSettings(page)
|
||||
await openFirstNote(page)
|
||||
await setMockGitCommitFailure(page, 'Author identity unknown')
|
||||
|
||||
await seedSavedChange(page)
|
||||
await expectCommitAttemptCount(page, 1)
|
||||
await expectDirtyPathCount(page, 1)
|
||||
await expect(page.locator('.fixed.bottom-8')).toContainText('Set a Git author before AutoGit can commit', { timeout: 5_000 })
|
||||
|
||||
await page.waitForTimeout(3_500)
|
||||
await expectCommitAttemptCount(page, 1)
|
||||
|
||||
await seedSavedChange(page)
|
||||
await expectCommitAttemptCount(page, 2)
|
||||
})
|
||||
Loading…
Reference in a new issue