mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-12 23:54:01 +09:00
test(dashboard): pin the scroll and keep the test QueryClient at its defaults
Deleting scrollIntoView left every focus test green, though it is the only thing that brings the field into view: focus is called with preventScroll, which turns off the browser's own scroll-on-focus. So the behaviour the fix exists for was unpinned. Stub scrollIntoView, which jsdom does not implement, and assert it. Same for the selector escaping, which only the fallback path reaches, so the test has to miss the exact id for an unescaped quote to break anything. Keep the test QueryClient at retry and gcTime only. No test needs the wider production defaults: the suite is green either way, while staleTime and placeholderData change what all 53 files observe. It belongs with the change that needs it. Record the new schema keyword in the console notes. Assisted-by: LLM Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
This commit is contained in:
1 parent
c0cb7a3646
commit
98e579c845
3 files changed
+28
-13
No files matched your search
@@ -100,6 +100,7 @@ schema). The pipeline in `apps/console/src/components/SchemaForm.tsx`:
|
||||
3. A chain of `addXxxWidgets(schema, uiSchema)` walks the schema and binds
|
||||
widgets:
|
||||
- any field carrying the `x-cozystack-options` schema keyword → `DynamicOptionsWidget`, a runtime dropdown populated from the cluster's `Option` resource (`core.cozystack.io`) keyed by the keyword's `source`; `addDynamicOptionWidgets` (`lib/dynamic-options.ts`) recurses into `properties`, array `items` and `additionalProperties`, and replaces the former field-name-bound `StorageClassWidget` / `BackupClassWidget` / `VMDiskWidget`.
|
||||
- object carrying `x-cozystack-no-enable-switch: true` → rendered by `CustomObjectFieldTemplate` as a fieldset saying it has no enable switch and that an `enabled` field in YAML does nothing. Declared in `values.yaml` as `## @x-cozystack-no-enable-switch true` on the `@field` line it belongs to, and generated through to `values.schema.json` and the ApplicationDefinition. Must be declared rather than inferred from the object's fields: an unrelated `valuesOverride`-only object would otherwise inherit the copy, and adding a second field would silently drop it.
|
||||
- object with `additionalProperties: <schema>` → `AdditionalPropertiesField`
|
||||
- credential-shaped fields (`password`, `*token`, `*accessKey`, …) →
|
||||
`SensitiveStringWidget` — see `lib/sensitive-fields.ts` and its tests for
|
||||
|
||||
+26
-1
@@ -1,9 +1,14 @@
|
||||
import { describe, it, expect, beforeEach } from "vitest"
|
||||
import { describe, it, expect, beforeEach, vi } from "vitest"
|
||||
import { focusFirstError } from "@/lib/focus-first-error.ts"
|
||||
|
||||
describe("focusFirstError", () => {
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = ""
|
||||
// jsdom has no layout, so scrollIntoView is absent. Stub it so the call can
|
||||
// be asserted: focus() is passed preventScroll, which disables the
|
||||
// browser's own scroll-on-focus, making this the only thing that brings
|
||||
// the field into view.
|
||||
HTMLElement.prototype.scrollIntoView = vi.fn()
|
||||
})
|
||||
|
||||
it("focuses the field carrying the generated id", () => {
|
||||
@@ -122,6 +127,26 @@ describe("focusFirstError", () => {
|
||||
expect(document.activeElement).toBe(field)
|
||||
})
|
||||
|
||||
it("scrolls the field into view, not only focuses it", () => {
|
||||
document.body.innerHTML = `<input id="root_name" />`
|
||||
const field = document.getElementById("root_name") as HTMLElement
|
||||
|
||||
focusFirstError({ property: ".name" })
|
||||
|
||||
expect(field.scrollIntoView).toHaveBeenCalledWith({ block: "center" })
|
||||
})
|
||||
|
||||
it("escapes a quote in the generated id rather than breaking the selector", () => {
|
||||
// Only the fallback interpolates the id into a quoted attribute selector,
|
||||
// so the exact lookup has to miss for this to bite: an unescaped quote
|
||||
// ends the selector string early and querySelector throws SyntaxError.
|
||||
document.body.innerHTML = `<input id='root_a"b_child' />`
|
||||
const field = document.getElementById('root_a"b_child')
|
||||
|
||||
expect(() => focusFirstError({ property: '.a"b' })).not.toThrow()
|
||||
expect(document.activeElement).toBe(field)
|
||||
})
|
||||
|
||||
it("does nothing when the field is nowhere in the document", () => {
|
||||
document.body.innerHTML = `<input id="root_other" />`
|
||||
|
||||
|
||||
@@ -19,19 +19,8 @@ export function renderWithK8sProvider(
|
||||
ui: ReactElement,
|
||||
options: RenderWithK8sOptions,
|
||||
): RenderResult & { queryClient: QueryClient } {
|
||||
// Mirror the production defaults in `K8sProvider` that change what a
|
||||
// component observes: `placeholderData` serves the previous query's data
|
||||
// with status "success" when the key changes, so a test client without it
|
||||
// never sees the window where `isLoading` is false but the data is stale.
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
retry: false,
|
||||
gcTime: 0,
|
||||
staleTime: 30_000,
|
||||
placeholderData: (prev: unknown) => prev,
|
||||
},
|
||||
},
|
||||
defaultOptions: { queries: { retry: false, gcTime: 0 } },
|
||||
})
|
||||
const result = render(
|
||||
<K8sProvider client={options.client} queryClient={queryClient}>
|
||||
|
||||
Reference in new issue
Block a user