parent
af233b8fb3
commit
d36cd3b1f8
|
@ -56,6 +56,7 @@ jobs:
|
|||
run: yarn install:pro $BRANCH $BASE_BRANCH
|
||||
- run: yarn
|
||||
- run: yarn bootstrap
|
||||
- run: yarn build
|
||||
- run: yarn test
|
||||
- uses: codecov/codecov-action@v3
|
||||
with:
|
||||
|
@ -94,4 +95,4 @@ jobs:
|
|||
yarn test:ci
|
||||
env:
|
||||
BB_ADMIN_USER_EMAIL: admin
|
||||
BB_ADMIN_USER_PASSWORD: admin
|
||||
BB_ADMIN_USER_PASSWORD: admin
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
<TooltipWrapper {tooltip} {size}>
|
||||
<label
|
||||
data-testid="label"
|
||||
class:muted
|
||||
for=""
|
||||
class={`spectrum-FieldLabel spectrum-FieldLabel--size${size}`}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
</script>
|
||||
|
||||
<p
|
||||
data-testid="typography-body"
|
||||
style={`
|
||||
${weight ? `font-weight:${weight};` : ""}
|
||||
${textAlign ? `text-align:${textAlign};` : ""}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
</script>
|
||||
|
||||
<h1
|
||||
data-testid="typography-heading"
|
||||
style={textAlign ? `text-align:${textAlign}` : ``}
|
||||
class:noPadding
|
||||
class="spectrum-Heading spectrum-Heading--size{size} spectrum-Heading--{weight}"
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
"dev:builder": "routify -c dev:vite",
|
||||
"dev:vite": "vite --host 0.0.0.0",
|
||||
"rollup": "rollup -c -w",
|
||||
"test": "jest"
|
||||
"test": "vitest"
|
||||
},
|
||||
"jest": {
|
||||
"globals": {
|
||||
|
@ -93,13 +93,14 @@
|
|||
"@roxi/routify": "2.18.5",
|
||||
"@sveltejs/vite-plugin-svelte": "1.0.1",
|
||||
"@testing-library/jest-dom": "^5.11.10",
|
||||
"@testing-library/svelte": "^3.0.0",
|
||||
"@testing-library/svelte": "^3.2.2",
|
||||
"babel-jest": "^26.6.3",
|
||||
"cypress": "^9.3.1",
|
||||
"cypress-multi-reporters": "^1.6.0",
|
||||
"cypress-terminal-report": "^1.4.1",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jest": "^26.6.3",
|
||||
"jsdom": "^21.1.1",
|
||||
"mochawesome": "^7.1.3",
|
||||
"mochawesome-merge": "^4.2.1",
|
||||
"mochawesome-report-generator": "^6.2.0",
|
||||
|
@ -113,7 +114,8 @@
|
|||
"ts-node": "10.8.1",
|
||||
"tsconfig-paths": "4.0.0",
|
||||
"typescript": "4.7.3",
|
||||
"vite": "^3.0.8"
|
||||
"vite": "^3.0.8",
|
||||
"vitest": "^0.29.2"
|
||||
},
|
||||
"gitHead": "115189f72a850bfb52b65ec61d932531bf327072"
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import * as jsonpatch from "fast-json-patch/index.mjs"
|
||||
import { writable, derived, get } from "svelte/store"
|
||||
|
||||
const Operations = {
|
||||
export const Operations = {
|
||||
Add: "Add",
|
||||
Delete: "Delete",
|
||||
Change: "Change",
|
||||
}
|
||||
|
||||
const initialState = {
|
||||
export const initialState = {
|
||||
history: [],
|
||||
position: 0,
|
||||
loading: false,
|
||||
|
|
|
@ -0,0 +1,345 @@
|
|||
import { it, expect, describe, beforeEach, vi } from "vitest"
|
||||
import { Operations, initialState, createHistoryStore } from "./history"
|
||||
|
||||
import { writable, derived, get } from "svelte/store"
|
||||
import * as jsonpatch from "fast-json-patch/index.mjs"
|
||||
|
||||
vi.mock("svelte/store", () => {
|
||||
return {
|
||||
writable: vi.fn(),
|
||||
derived: vi.fn(),
|
||||
get: vi.fn(),
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock("fast-json-patch/index.mjs", () => {
|
||||
return {
|
||||
compare: vi.fn(),
|
||||
deepClone: vi.fn(),
|
||||
applyPatch: vi.fn(),
|
||||
}
|
||||
})
|
||||
|
||||
describe("admin store", () => {
|
||||
beforeEach(ctx => {
|
||||
vi.clearAllMocks()
|
||||
|
||||
ctx.writableReturn = { update: vi.fn(), subscribe: vi.fn(), set: vi.fn() }
|
||||
writable.mockReturnValue(ctx.writableReturn)
|
||||
|
||||
ctx.derivedReturn = { subscribe: vi.fn() }
|
||||
derived.mockReturnValue(ctx.derivedReturn)
|
||||
|
||||
ctx.getDoc = vi.fn().mockReturnValue({})
|
||||
ctx.selectDoc = vi.fn().mockReturnValue({})
|
||||
ctx.beforeAction = vi.fn()
|
||||
ctx.afterAction = vi.fn()
|
||||
|
||||
ctx.returnedStore = createHistoryStore({
|
||||
getDoc: ctx.getDoc,
|
||||
selectDoc: ctx.selectDoc,
|
||||
beforeAction: ctx.beforeAction,
|
||||
afterAction: ctx.afterAction,
|
||||
})
|
||||
})
|
||||
|
||||
describe("init", () => {
|
||||
it("inits the writable store with the default config", () => {
|
||||
expect(writable).toHaveBeenCalledTimes(1)
|
||||
expect(writable).toHaveBeenCalledWith(initialState)
|
||||
})
|
||||
|
||||
it("inits the derived store with the initial writable store and an update function", () => {
|
||||
expect(derived).toHaveBeenCalledTimes(1)
|
||||
expect(derived.calls[0][1]({ position: 0, history: [] })).toEqual({
|
||||
position: 0,
|
||||
history: [],
|
||||
canUndo: false,
|
||||
canRedo: false,
|
||||
})
|
||||
})
|
||||
|
||||
it("returns the created store and methods to manipulate it", ctx => {
|
||||
expect(ctx.returnedStore).toEqual({
|
||||
subscribe: expect.toBe(ctx.derivedReturn.subscribe),
|
||||
wrapSaveDoc: expect.toBeFunc(),
|
||||
wrapDeleteDoc: expect.toBeFunc(),
|
||||
reset: expect.toBeFunc(),
|
||||
undo: expect.toBeFunc(),
|
||||
redo: expect.toBeFunc(),
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("wrapSaveDoc", () => {
|
||||
beforeEach(async ctx => {
|
||||
ctx.saveFn = vi.fn().mockResolvedValue("fn")
|
||||
|
||||
ctx.doc = { _id: "id" }
|
||||
ctx.oldDoc = { _id: "oldDoc" }
|
||||
ctx.newDoc = { _id: "newDoc" }
|
||||
ctx.getDoc.mockReturnValue(ctx.oldDoc)
|
||||
jsonpatch.deepClone.mockReturnValue(ctx.newDoc)
|
||||
|
||||
vi.stubGlobal("Math", { random: vi.fn() })
|
||||
|
||||
ctx.forwardPatch = { foo: 1 }
|
||||
ctx.backwardsPatch = { bar: 2 }
|
||||
|
||||
jsonpatch.compare.mockReturnValueOnce(ctx.forwardPatch)
|
||||
jsonpatch.compare.mockReturnValueOnce(ctx.backwardsPatch)
|
||||
Math.random.mockReturnValue(1234)
|
||||
|
||||
const wrappedSaveFn = ctx.returnedStore.wrapSaveDoc(ctx.saveFn)
|
||||
await wrappedSaveFn(ctx.doc, null)
|
||||
})
|
||||
|
||||
it("sets the state to loading", ctx => {
|
||||
expect(ctx.writableReturn.update.calls[0][0]({})).toEqual({
|
||||
loading: true,
|
||||
})
|
||||
})
|
||||
|
||||
it("retrieves the old doc", ctx => {
|
||||
expect(ctx.getDoc).toHaveBeenCalledTimes(1)
|
||||
expect(ctx.getDoc).toHaveBeenCalledWith("id")
|
||||
})
|
||||
|
||||
it("clones the new doc", ctx => {
|
||||
expect(ctx.saveFn).toHaveBeenCalledTimes(1)
|
||||
expect(ctx.saveFn).toHaveBeenCalledWith(ctx.doc)
|
||||
expect(jsonpatch.deepClone).toHaveBeenCalledTimes(1)
|
||||
expect(jsonpatch.deepClone).toHaveBeenCalledWith("fn")
|
||||
})
|
||||
|
||||
it("creates the undo/redo patches", ctx => {
|
||||
expect(jsonpatch.compare).toHaveBeenCalledTimes(2)
|
||||
expect(jsonpatch.compare.calls[0]).toEqual([ctx.oldDoc, ctx.doc])
|
||||
expect(jsonpatch.compare.calls[1]).toEqual([ctx.doc, ctx.oldDoc])
|
||||
})
|
||||
|
||||
it("saves the operation", ctx => {
|
||||
expect(
|
||||
ctx.writableReturn.update.calls[1][0]({
|
||||
history: [],
|
||||
position: 0,
|
||||
})
|
||||
).toEqual({
|
||||
history: [
|
||||
{
|
||||
type: Operations.Change,
|
||||
backwardsPatch: ctx.backwardsPatch,
|
||||
forwardPatch: ctx.forwardPatch,
|
||||
doc: ctx.newDoc,
|
||||
id: 1234,
|
||||
},
|
||||
],
|
||||
position: 1,
|
||||
})
|
||||
})
|
||||
|
||||
it("sets the state to not loading", ctx => {
|
||||
expect(ctx.writableReturn.update).toHaveBeenCalledTimes(3)
|
||||
expect(ctx.writableReturn.update.calls[2][0]({})).toEqual({
|
||||
loading: false,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("wrapDeleteDoc", () => {
|
||||
beforeEach(async ctx => {
|
||||
ctx.deleteFn = vi.fn().mockResolvedValue("fn")
|
||||
|
||||
ctx.doc = { _id: "id" }
|
||||
ctx.oldDoc = { _id: "oldDoc" }
|
||||
jsonpatch.deepClone.mockReturnValue(ctx.oldDoc)
|
||||
|
||||
vi.stubGlobal("Math", { random: vi.fn() })
|
||||
Math.random.mockReturnValue(1235)
|
||||
|
||||
const wrappedDeleteDoc = ctx.returnedStore.wrapDeleteDoc(ctx.deleteFn)
|
||||
await wrappedDeleteDoc(ctx.doc, null)
|
||||
})
|
||||
|
||||
it("sets the state to loading", ctx => {
|
||||
expect(ctx.writableReturn.update.calls[0][0]({})).toEqual({
|
||||
loading: true,
|
||||
})
|
||||
})
|
||||
|
||||
it("clones the doc", ctx => {
|
||||
expect(jsonpatch.deepClone).toHaveBeenCalledTimes(1)
|
||||
expect(jsonpatch.deepClone).toHaveBeenCalledWith(ctx.doc)
|
||||
})
|
||||
|
||||
it("calls the delete fn with the doc", ctx => {
|
||||
expect(ctx.deleteFn).toHaveBeenCalledTimes(1)
|
||||
expect(ctx.deleteFn).toHaveBeenCalledWith(ctx.doc)
|
||||
})
|
||||
|
||||
it("saves the operation", ctx => {
|
||||
expect(
|
||||
ctx.writableReturn.update.calls[1][0]({
|
||||
history: [],
|
||||
position: 0,
|
||||
})
|
||||
).toEqual({
|
||||
history: [
|
||||
{
|
||||
type: Operations.Delete,
|
||||
doc: ctx.oldDoc,
|
||||
id: 1235,
|
||||
},
|
||||
],
|
||||
position: 1,
|
||||
})
|
||||
})
|
||||
|
||||
it("sets the state to not loading", ctx => {
|
||||
expect(ctx.writableReturn.update).toHaveBeenCalledTimes(3)
|
||||
expect(ctx.writableReturn.update.calls[2][0]({})).toEqual({
|
||||
loading: false,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("reset", () => {
|
||||
beforeEach(ctx => {
|
||||
ctx.returnedStore.reset()
|
||||
})
|
||||
|
||||
it("sets the store to the initial state", ctx => {
|
||||
expect(ctx.writableReturn.set).toHaveBeenCalledTimes(1)
|
||||
expect(ctx.writableReturn.set).toHaveBeenCalledWith(initialState)
|
||||
})
|
||||
})
|
||||
|
||||
describe("undo", () => {
|
||||
beforeEach(async ctx => {
|
||||
ctx.history = [
|
||||
{ type: Operations.Delete, doc: { _id: 1236, _rev: "rev" } },
|
||||
]
|
||||
ctx.derivedReturn = {
|
||||
subscribe: vi.fn(),
|
||||
canUndo: true,
|
||||
history: ctx.history,
|
||||
position: 1,
|
||||
loading: false,
|
||||
}
|
||||
get.mockReturnValue(ctx.derivedReturn)
|
||||
|
||||
jsonpatch.deepClone.mockReturnValueOnce(ctx.history[0].doc)
|
||||
|
||||
ctx.newDoc = { _id: 1337 }
|
||||
ctx.saveFn = vi.fn().mockResolvedValue(ctx.newDoc)
|
||||
jsonpatch.deepClone.mockReturnValueOnce(ctx.newDoc)
|
||||
|
||||
// We need to create a wrapped saveFn before undo can be invoked
|
||||
ctx.returnedStore.wrapSaveDoc(ctx.saveFn)
|
||||
await ctx.returnedStore.undo()
|
||||
})
|
||||
|
||||
it("sets the state to loading", ctx => {
|
||||
expect(ctx.writableReturn.update.calls[0][0]({})).toEqual({
|
||||
loading: true,
|
||||
})
|
||||
})
|
||||
|
||||
it("calls the beforeAction", ctx => {
|
||||
expect(ctx.beforeAction).toHaveBeenCalledTimes(1)
|
||||
expect(ctx.beforeAction).toHaveBeenCalledWith(ctx.history[0])
|
||||
})
|
||||
|
||||
it("sets the state to the previous position", ctx => {
|
||||
expect(
|
||||
ctx.writableReturn.update.calls[1][0]({ history: [], position: 1 })
|
||||
).toEqual({ history: [], position: 0 })
|
||||
})
|
||||
|
||||
it("clones the doc", ctx => {
|
||||
expect(jsonpatch.deepClone).toHaveBeenCalledWith(ctx.history[0].doc)
|
||||
})
|
||||
|
||||
it("deletes the doc's rev", ctx => {
|
||||
expect(ctx.history[0].doc._rev).toBe(undefined)
|
||||
})
|
||||
|
||||
it("calls the wrappedSaveFn", ctx => {
|
||||
expect(jsonpatch.deepClone).toHaveBeenCalledWith(ctx.newDoc)
|
||||
expect(ctx.saveFn).toHaveBeenCalledWith(ctx.history[0].doc)
|
||||
})
|
||||
|
||||
it("calls selectDoc", ctx => {
|
||||
expect(ctx.selectDoc).toHaveBeenCalledWith(ctx.newDoc._id)
|
||||
})
|
||||
|
||||
it("sets the state to not loading", ctx => {
|
||||
expect(ctx.writableReturn.update.calls[5][0]({})).toEqual({
|
||||
loading: false,
|
||||
})
|
||||
})
|
||||
|
||||
it("calls the afterAction", ctx => {
|
||||
expect(ctx.afterAction).toHaveBeenCalledTimes(1)
|
||||
expect(ctx.afterAction).toHaveBeenCalledWith(ctx.history[0])
|
||||
})
|
||||
})
|
||||
|
||||
describe("redo", () => {
|
||||
beforeEach(async ctx => {
|
||||
ctx.history = [
|
||||
{ type: Operations.Delete, doc: { _id: 1236, _rev: "rev" } },
|
||||
]
|
||||
ctx.derivedReturn = {
|
||||
subscribe: vi.fn(),
|
||||
canRedo: true,
|
||||
history: ctx.history,
|
||||
position: 0,
|
||||
loading: false,
|
||||
}
|
||||
|
||||
get.mockReturnValue(ctx.derivedReturn)
|
||||
|
||||
ctx.latestDoc = { _id: 1337 }
|
||||
ctx.getDoc.mockReturnValue(ctx.latestDoc)
|
||||
|
||||
// We need to create a wrapped deleteFn before redo can be invoked
|
||||
ctx.deleteFn = vi.fn().mockResolvedValue(ctx.newDoc)
|
||||
ctx.returnedStore.wrapDeleteDoc(ctx.deleteFn)
|
||||
|
||||
await ctx.returnedStore.redo()
|
||||
})
|
||||
|
||||
it("sets the state to loading", ctx => {
|
||||
expect(ctx.writableReturn.update.calls[0][0]({})).toEqual({
|
||||
loading: true,
|
||||
})
|
||||
})
|
||||
|
||||
it("calls the beforeAction", ctx => {
|
||||
expect(ctx.beforeAction).toHaveBeenCalledTimes(1)
|
||||
expect(ctx.beforeAction).toHaveBeenCalledWith(ctx.history[0])
|
||||
})
|
||||
|
||||
it("sets the state to the next position", ctx => {
|
||||
expect(
|
||||
ctx.writableReturn.update.calls[1][0]({ history: [], position: 0 })
|
||||
).toEqual({ history: [], position: 1 })
|
||||
})
|
||||
|
||||
it("calls the wrappedDeleteFn", ctx => {
|
||||
expect(ctx.deleteFn).toHaveBeenCalledWith(ctx.latestDoc)
|
||||
})
|
||||
|
||||
it("sets the state to not loading", ctx => {
|
||||
expect(ctx.writableReturn.update.calls[5][0]({})).toEqual({
|
||||
loading: false,
|
||||
})
|
||||
})
|
||||
|
||||
it("calls the afterAction", ctx => {
|
||||
expect(ctx.afterAction).toHaveBeenCalledTimes(1)
|
||||
expect(ctx.afterAction).toHaveBeenCalledWith(ctx.history[0])
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,37 @@
|
|||
import { it, expect, describe, beforeEach } from "vitest"
|
||||
import { render, screen } from "@testing-library/svelte"
|
||||
import "@testing-library/jest-dom"
|
||||
|
||||
import EditableLabel from "./EditableLabel.svelte"
|
||||
|
||||
describe("EditableLabel", () => {
|
||||
describe('type of "heading"', () => {
|
||||
beforeEach(() => {
|
||||
render(EditableLabel, { type: "heading", value: "foo" })
|
||||
})
|
||||
|
||||
it("renders a heading", () => {
|
||||
expect(screen.getByTestId("typography-heading")).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
describe('type of "body"', () => {
|
||||
beforeEach(() => {
|
||||
render(EditableLabel, { type: "body", value: "foo" })
|
||||
})
|
||||
|
||||
it("renders a body", () => {
|
||||
expect(screen.getByTestId("typography-body")).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
describe("any other type", () => {
|
||||
beforeEach(() => {
|
||||
render(EditableLabel, { type: "", value: "foo" })
|
||||
})
|
||||
|
||||
it("renders a label", () => {
|
||||
expect(screen.getByTestId("label")).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,3 +1,4 @@
|
|||
import { expect, describe, it } from "vitest"
|
||||
import { breakQueryString, buildQueryString } from "../data/utils"
|
||||
|
||||
describe("check query string utils", () => {
|
||||
|
@ -26,12 +27,16 @@ describe("check query string utils", () => {
|
|||
|
||||
it("should be able to build with a binding", () => {
|
||||
const queryString = buildQueryString(obj2)
|
||||
expect(queryString).toBe("key1={{ binding.awd }}&key2={{ binding.sed }}%20%20")
|
||||
expect(queryString).toBe(
|
||||
"key1={{ binding.awd }}&key2={{ binding.sed }}%20%20"
|
||||
)
|
||||
})
|
||||
|
||||
it("should be able to break with a binding", () => {
|
||||
const broken = breakQueryString("key1={{ binding.awd }}&key2={{ binding.sed }}%20%20")
|
||||
const broken = breakQueryString(
|
||||
"key1={{ binding.awd }}&key2={{ binding.sed }}%20%20"
|
||||
)
|
||||
expect(broken.key1).toBe(obj2.key1)
|
||||
expect(broken.key2).toBe(obj2.key2)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,7 +1,7 @@
|
|||
const { duplicateName } = require("../duplicate")
|
||||
import { expect, describe, it } from "vitest"
|
||||
import { duplicateName } from "../duplicate"
|
||||
|
||||
describe("duplicate", () => {
|
||||
|
||||
describe("duplicates a name ", () => {
|
||||
it("with a single existing", async () => {
|
||||
const names = ["foo"]
|
|
@ -3,23 +3,23 @@ import { API } from "api"
|
|||
import { auth } from "stores/portal"
|
||||
import { banner } from "@budibase/bbui"
|
||||
|
||||
export function createAdminStore() {
|
||||
const DEFAULT_CONFIG = {
|
||||
loaded: false,
|
||||
multiTenancy: false,
|
||||
cloud: false,
|
||||
isDev: false,
|
||||
disableAccountPortal: false,
|
||||
accountPortalUrl: "",
|
||||
importComplete: false,
|
||||
checklist: {
|
||||
apps: { checked: false },
|
||||
smtp: { checked: false },
|
||||
adminUser: { checked: false },
|
||||
sso: { checked: false },
|
||||
},
|
||||
}
|
||||
export const DEFAULT_CONFIG = {
|
||||
loaded: false,
|
||||
multiTenancy: false,
|
||||
cloud: false,
|
||||
isDev: false,
|
||||
disableAccountPortal: false,
|
||||
accountPortalUrl: "",
|
||||
importComplete: false,
|
||||
checklist: {
|
||||
apps: { checked: false },
|
||||
smtp: { checked: false },
|
||||
adminUser: { checked: false },
|
||||
sso: { checked: false },
|
||||
},
|
||||
}
|
||||
|
||||
export function createAdminStore() {
|
||||
const admin = writable(DEFAULT_CONFIG)
|
||||
|
||||
async function init() {
|
||||
|
|
|
@ -0,0 +1,268 @@
|
|||
import { it, expect, describe, beforeEach, vi } from "vitest"
|
||||
import { DEFAULT_CONFIG, createAdminStore } from "./admin"
|
||||
|
||||
import { writable, get } from "svelte/store"
|
||||
import { API } from "api"
|
||||
import { auth } from "stores/portal"
|
||||
import { banner } from "@budibase/bbui"
|
||||
|
||||
vi.mock("stores/portal", () => {
|
||||
return { auth: vi.fn() }
|
||||
})
|
||||
|
||||
// explict mock that is overwritten later so that the singleton admin store doesn't throw an error when partially mocked
|
||||
vi.mock("svelte/store", () => {
|
||||
return {
|
||||
writable: vi.fn(() => ({
|
||||
subscribe: vi.fn(),
|
||||
update: vi.fn(),
|
||||
})),
|
||||
get: vi.fn(),
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock("api", () => {
|
||||
return {
|
||||
API: {
|
||||
checkImportComplete: vi.fn(),
|
||||
getEnvironment: vi.fn(),
|
||||
getSystemStatus: vi.fn(),
|
||||
getChecklist: vi.fn(),
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock("@budibase/bbui", () => {
|
||||
return { banner: { showStatus: vi.fn() } }
|
||||
})
|
||||
|
||||
describe("admin store", () => {
|
||||
beforeEach(ctx => {
|
||||
vi.clearAllMocks()
|
||||
|
||||
ctx.writableReturn = { update: vi.fn(), subscribe: vi.fn() }
|
||||
writable.mockReturnValue(ctx.writableReturn)
|
||||
|
||||
ctx.returnedStore = createAdminStore()
|
||||
})
|
||||
|
||||
it("inits the writable store with the default config", () => {
|
||||
expect(writable).toHaveBeenCalledTimes(1)
|
||||
expect(writable).toHaveBeenCalledWith(DEFAULT_CONFIG)
|
||||
})
|
||||
|
||||
it("returns the created store", ctx => {
|
||||
expect(ctx.returnedStore).toEqual({
|
||||
subscribe: expect.toBe(ctx.writableReturn.subscribe),
|
||||
init: expect.toBeFunc(),
|
||||
checkImportComplete: expect.toBeFunc(),
|
||||
unload: expect.toBeFunc(),
|
||||
getChecklist: expect.toBeFunc(),
|
||||
})
|
||||
})
|
||||
|
||||
describe("init method", () => {
|
||||
beforeEach(async ctx => {
|
||||
let getMockIndex = 0
|
||||
|
||||
ctx.getMockValues = [
|
||||
{ tenantId: "tenantId" },
|
||||
{ cloud: true },
|
||||
{ status: { health: { passing: false } } },
|
||||
]
|
||||
|
||||
get.mockImplementation(() => {
|
||||
const value = ctx.getMockValues[getMockIndex]
|
||||
getMockIndex++
|
||||
|
||||
return value
|
||||
})
|
||||
|
||||
API.getChecklist.mockReturnValue("checklist")
|
||||
|
||||
API.getEnvironment.mockReturnValue({
|
||||
multiTenancy: true,
|
||||
cloud: true,
|
||||
disableAccountPortal: true,
|
||||
accountPortalUrl: "url",
|
||||
isDev: true,
|
||||
})
|
||||
|
||||
API.getSystemStatus.mockReturnValue("status")
|
||||
})
|
||||
|
||||
describe("getCheckList", () => {
|
||||
beforeEach(async ctx => {
|
||||
await ctx.returnedStore.init()
|
||||
})
|
||||
|
||||
it("adds the checklist to the store", ctx => {
|
||||
expect(get).toHaveBeenNthCalledWith(1, auth)
|
||||
expect(API.getChecklist).toHaveBeenCalledTimes(1)
|
||||
expect(API.getChecklist).toHaveBeenCalledWith("tenantId")
|
||||
expect(ctx.writableReturn.update.calls[0][0]({ foo: "foo" })).toEqual({
|
||||
foo: "foo",
|
||||
checklist: "checklist",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("getEnvironment", () => {
|
||||
beforeEach(async ctx => {
|
||||
await ctx.returnedStore.init()
|
||||
})
|
||||
|
||||
it("adds the environment to the store", ctx => {
|
||||
expect(API.getEnvironment).toHaveBeenCalledTimes(1)
|
||||
expect(API.getEnvironment).toHaveBeenCalledWith()
|
||||
expect(ctx.writableReturn.update.calls[1][0]({ foo: "foo" })).toEqual({
|
||||
foo: "foo",
|
||||
multiTenancy: true,
|
||||
cloud: true,
|
||||
disableAccountPortal: true,
|
||||
accountPortalUrl: "url",
|
||||
isDev: true,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("system status", () => {
|
||||
describe("non cloud", () => {
|
||||
beforeEach(async ctx => {
|
||||
ctx.getMockValues[1].cloud = false
|
||||
await ctx.returnedStore.init()
|
||||
})
|
||||
|
||||
it("getSystemStatus", () => {
|
||||
expect(API.getSystemStatus).toHaveBeenCalledTimes(0)
|
||||
})
|
||||
|
||||
it("checkStatus", () => {
|
||||
expect(get).toHaveBeenCalledTimes(2)
|
||||
expect(banner.showStatus).toHaveBeenCalledTimes(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe("cloud with healthy admin status", () => {
|
||||
beforeEach(async ctx => {
|
||||
ctx.getMockValues[1].cloud = true
|
||||
ctx.getMockValues[2].status.health.passing = true
|
||||
await ctx.returnedStore.init()
|
||||
})
|
||||
|
||||
it("getSystemStatus", ctx => {
|
||||
expect(get).toHaveBeenNthCalledWith(2, ctx.writableReturn)
|
||||
expect(API.getSystemStatus).toHaveBeenCalledTimes(1)
|
||||
expect(API.getEnvironment).toHaveBeenCalledWith()
|
||||
expect(ctx.writableReturn.update.calls[2][0]({ foo: "foo" })).toEqual(
|
||||
{ foo: "foo", status: "status" }
|
||||
)
|
||||
})
|
||||
|
||||
it("checkStatus", ctx => {
|
||||
expect(get).toHaveBeenCalledTimes(3)
|
||||
expect(get).toHaveBeenNthCalledWith(3, ctx.writableReturn)
|
||||
expect(banner.showStatus).toHaveBeenCalledTimes(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe("cloud with unhealthy admin status", () => {
|
||||
beforeEach(async ctx => {
|
||||
ctx.getMockValues[1].cloud = true
|
||||
ctx.getMockValues[2].status.health.passing = false
|
||||
await ctx.returnedStore.init()
|
||||
})
|
||||
|
||||
it("getSystemStatus", ctx => {
|
||||
expect(get).toHaveBeenNthCalledWith(2, ctx.writableReturn)
|
||||
expect(API.getSystemStatus).toHaveBeenCalledTimes(1)
|
||||
expect(API.getEnvironment).toHaveBeenCalledWith()
|
||||
expect(ctx.writableReturn.update.calls[2][0]({ foo: "foo" })).toEqual(
|
||||
{ foo: "foo", status: "status" }
|
||||
)
|
||||
})
|
||||
|
||||
it("checkStatus", ctx => {
|
||||
expect(get).toHaveBeenCalledTimes(3)
|
||||
expect(get).toHaveBeenNthCalledWith(3, ctx.writableReturn)
|
||||
expect(banner.showStatus).toHaveBeenCalledTimes(1)
|
||||
expect(banner.showStatus).toHaveBeenCalledWith()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("getEnvironment", () => {
|
||||
beforeEach(async ctx => {
|
||||
await ctx.returnedStore.init()
|
||||
})
|
||||
|
||||
it("marks the store as loaded", ctx => {
|
||||
expect(ctx.writableReturn.update.calls[3][0]({ foo: "foo" })).toEqual({
|
||||
foo: "foo",
|
||||
loaded: true,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("checkImportComplete", () => {
|
||||
describe("import complete", () => {
|
||||
beforeEach(async ctx => {
|
||||
API.checkImportComplete.mockReturnValue({ imported: true })
|
||||
await ctx.returnedStore.checkImportComplete()
|
||||
})
|
||||
|
||||
it("updates the store's importComplete parameter", ctx => {
|
||||
expect(ctx.writableReturn.update.calls[0][0]({ foo: "foo" })).toEqual({
|
||||
foo: "foo",
|
||||
importComplete: true,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("import not complete", () => {
|
||||
beforeEach(async ctx => {
|
||||
// Can be null
|
||||
API.checkImportComplete.mockReturnValue(null)
|
||||
await ctx.returnedStore.checkImportComplete()
|
||||
})
|
||||
|
||||
it("updates the store's importComplete parameter", ctx => {
|
||||
expect(ctx.writableReturn.update.calls[0][0]({ foo: "foo" })).toEqual({
|
||||
foo: "foo",
|
||||
importComplete: false,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("unload", () => {
|
||||
beforeEach(ctx => {
|
||||
ctx.returnedStore.unload()
|
||||
})
|
||||
|
||||
it("sets the store's loaded parameter to false", ctx => {
|
||||
expect(ctx.writableReturn.update.calls[0][0]({ loaded: true })).toEqual({
|
||||
loaded: false,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("getChecklist", () => {
|
||||
beforeEach(async ctx => {
|
||||
get.mockReturnValue({ tenantId: "tenantId" })
|
||||
API.getChecklist.mockReturnValue("checklist")
|
||||
await ctx.returnedStore.getChecklist()
|
||||
})
|
||||
|
||||
it("updates the store with the new checklist", ctx => {
|
||||
expect(get).toHaveBeenNthCalledWith(1, auth)
|
||||
expect(API.getChecklist).toHaveBeenCalledTimes(1)
|
||||
expect(API.getChecklist).toHaveBeenCalledWith("tenantId")
|
||||
expect(ctx.writableReturn.update.calls[0][0]({ foo: "foo" })).toEqual({
|
||||
foo: "foo",
|
||||
checklist: "checklist",
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,173 @@
|
|||
import { it, expect, describe, beforeEach, vi } from "vitest"
|
||||
import { createBackupsStore } from "./backups"
|
||||
|
||||
import { writable } from "svelte/store"
|
||||
import { API } from "api"
|
||||
|
||||
vi.mock("svelte/store", () => {
|
||||
return {
|
||||
writable: vi.fn(() => ({
|
||||
subscribe: vi.fn(),
|
||||
update: vi.fn(),
|
||||
})),
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock("api", () => {
|
||||
return {
|
||||
API: {
|
||||
searchBackups: vi.fn(() => "searchBackupsReturn"),
|
||||
restoreBackup: vi.fn(() => "restoreBackupReturn"),
|
||||
deleteBackup: vi.fn(() => "deleteBackupReturn"),
|
||||
createManualBackup: vi.fn(() => "createManualBackupReturn"),
|
||||
updateBackup: vi.fn(() => "updateBackupReturn"),
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
describe("backups store", () => {
|
||||
beforeEach(ctx => {
|
||||
vi.clearAllMocks()
|
||||
|
||||
ctx.writableReturn = { update: vi.fn(), subscribe: vi.fn() }
|
||||
writable.mockReturnValue(ctx.writableReturn)
|
||||
|
||||
ctx.returnedStore = createBackupsStore()
|
||||
})
|
||||
|
||||
it("inits the writable store with the default config", () => {
|
||||
expect(writable).toHaveBeenCalledTimes(1)
|
||||
expect(writable).toHaveBeenCalledWith({})
|
||||
})
|
||||
|
||||
describe("createManualBackup", () => {
|
||||
beforeEach(async ctx => {
|
||||
ctx.appId = "appId"
|
||||
ctx.value = await ctx.returnedStore.createManualBackup(ctx.appId)
|
||||
})
|
||||
|
||||
it("calls and returns the API createManualBackup method", ctx => {
|
||||
expect(API.createManualBackup).toHaveBeenCalledTimes(1)
|
||||
expect(API.createManualBackup).toHaveBeenCalledWith(ctx.appId)
|
||||
expect(ctx.value).toBe("createManualBackupReturn")
|
||||
})
|
||||
})
|
||||
|
||||
describe("searchBackups", () => {
|
||||
beforeEach(async ctx => {
|
||||
ctx.appId = "appId"
|
||||
ctx.trigger = "trigger"
|
||||
ctx.type = "type"
|
||||
ctx.page = "page"
|
||||
ctx.startDate = "startDate"
|
||||
ctx.endDate = "endDate"
|
||||
ctx.value = await ctx.returnedStore.searchBackups({
|
||||
appId: ctx.appId,
|
||||
trigger: ctx.trigger,
|
||||
type: ctx.type,
|
||||
page: ctx.page,
|
||||
startDate: ctx.startDate,
|
||||
endDate: ctx.endDate,
|
||||
})
|
||||
})
|
||||
|
||||
it("calls and returns the API searchBackups method", ctx => {
|
||||
expect(API.searchBackups).toHaveBeenCalledTimes(1)
|
||||
expect(API.searchBackups).toHaveBeenCalledWith({
|
||||
appId: ctx.appId,
|
||||
trigger: ctx.trigger,
|
||||
type: ctx.type,
|
||||
page: ctx.page,
|
||||
startDate: ctx.startDate,
|
||||
endDate: ctx.endDate,
|
||||
})
|
||||
expect(ctx.value).toBe("searchBackupsReturn")
|
||||
})
|
||||
})
|
||||
|
||||
describe("selectBackup", () => {
|
||||
beforeEach(ctx => {
|
||||
ctx.backupId = "backupId"
|
||||
ctx.returnedStore.selectBackup(ctx.backupId)
|
||||
})
|
||||
|
||||
it("sets the state with the selected backup", ctx => {
|
||||
expect(ctx.writableReturn.update).toHaveBeenCalledTimes(1)
|
||||
expect(ctx.writableReturn.update.calls[0][0]({})).toEqual({
|
||||
selectedBackup: ctx.backupId,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("deleteBackup", () => {
|
||||
beforeEach(async ctx => {
|
||||
ctx.appId = "appId"
|
||||
ctx.backupId = "backupId"
|
||||
ctx.value = await ctx.returnedStore.deleteBackup({
|
||||
appId: ctx.appId,
|
||||
backupId: ctx.backupId,
|
||||
})
|
||||
})
|
||||
|
||||
it("calls and returns the API deleteBackup method", ctx => {
|
||||
expect(API.deleteBackup).toHaveBeenCalledTimes(1)
|
||||
expect(API.deleteBackup).toHaveBeenCalledWith({
|
||||
appId: ctx.appId,
|
||||
backupId: ctx.backupId,
|
||||
})
|
||||
expect(ctx.value).toBe("deleteBackupReturn")
|
||||
})
|
||||
})
|
||||
|
||||
describe("restoreBackup", () => {
|
||||
beforeEach(async ctx => {
|
||||
ctx.appId = "appId"
|
||||
ctx.backupId = "backupId"
|
||||
ctx.$name = "name" // `name` is used by some sort of internal ctx thing and is readonly
|
||||
ctx.value = await ctx.returnedStore.restoreBackup({
|
||||
appId: ctx.appId,
|
||||
backupId: ctx.backupId,
|
||||
name: ctx.$name,
|
||||
})
|
||||
})
|
||||
|
||||
it("calls and returns the API restoreBackup method", ctx => {
|
||||
expect(API.restoreBackup).toHaveBeenCalledTimes(1)
|
||||
expect(API.restoreBackup).toHaveBeenCalledWith({
|
||||
appId: ctx.appId,
|
||||
backupId: ctx.backupId,
|
||||
name: ctx.$name,
|
||||
})
|
||||
expect(ctx.value).toBe("restoreBackupReturn")
|
||||
})
|
||||
})
|
||||
|
||||
describe("updateBackup", () => {
|
||||
beforeEach(async ctx => {
|
||||
ctx.appId = "appId"
|
||||
ctx.backupId = "backupId"
|
||||
ctx.$name = "name" // `name` is used by some sort of internal ctx thing and is readonly
|
||||
ctx.value = await ctx.returnedStore.updateBackup({
|
||||
appId: ctx.appId,
|
||||
backupId: ctx.backupId,
|
||||
name: ctx.$name,
|
||||
})
|
||||
})
|
||||
|
||||
it("calls and returns the API updateBackup method", ctx => {
|
||||
expect(API.updateBackup).toHaveBeenCalledTimes(1)
|
||||
expect(API.updateBackup).toHaveBeenCalledWith({
|
||||
appId: ctx.appId,
|
||||
backupId: ctx.backupId,
|
||||
name: ctx.$name,
|
||||
})
|
||||
expect(ctx.value).toBe("updateBackupReturn")
|
||||
})
|
||||
})
|
||||
|
||||
describe("subscribe", () => {
|
||||
it("calls and returns the API updateBackup method", ctx => {
|
||||
expect(ctx.returnedStore.subscribe).toBe(ctx.writableReturn.subscribe)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -15,6 +15,11 @@ export default defineConfig(({ mode }) => {
|
|||
const isProduction = mode === "production"
|
||||
const env = loadEnv(mode, process.cwd())
|
||||
return {
|
||||
test: {
|
||||
setupFiles: ["./vitest.setup.js"],
|
||||
globals: true,
|
||||
environment: "jsdom",
|
||||
},
|
||||
server: {
|
||||
fs: {
|
||||
strict: false,
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
import { expect } from "vitest"
|
||||
|
||||
expect.extend({
|
||||
toBeFunc: received => {
|
||||
if (typeof received === "function") {
|
||||
return {
|
||||
pass: true,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
message: () => `expected ${received} to be a function`,
|
||||
pass: false,
|
||||
}
|
||||
},
|
||||
toBe: (received, expected) => {
|
||||
if (received === expected) {
|
||||
return {
|
||||
pass: true,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
message: () => `expected ${received} to be ${expected}`,
|
||||
pass: false,
|
||||
}
|
||||
},
|
||||
})
|
Loading…
Reference in New Issue