184 lines
6.9 KiB
JavaScript
184 lines
6.9 KiB
JavaScript
const { test } = require('node:test')
|
|
const assert = require('node:assert/strict')
|
|
const fs = require('node:fs')
|
|
const path = require('node:path')
|
|
const vm = require('node:vm')
|
|
const { createRequire } = require('node:module')
|
|
const vue = require('vue')
|
|
const { parse, compileScript, compileTemplate } = require('vue/compiler-sfc')
|
|
const esbuild = createRequire(require.resolve('vite'))('esbuild')
|
|
|
|
const directory = path.join(__dirname, '../src/views/health/identity')
|
|
const familyModule = { exports: {} }
|
|
vm.runInNewContext(
|
|
esbuild.transformSync(fs.readFileSync(path.join(directory, 'collectionFamily.ts'), 'utf8'), {
|
|
loader: 'ts',
|
|
format: 'cjs'
|
|
}).code,
|
|
{ module: familyModule, exports: familyModule.exports }
|
|
)
|
|
const helpers = familyModule.exports
|
|
const privacyModule = { exports: {} }
|
|
vm.runInNewContext(
|
|
esbuild.transformSync(
|
|
fs.readFileSync(path.join(__dirname, '../src/utils/healthPrivacy.ts'), 'utf8'),
|
|
{ loader: 'ts', format: 'cjs' }
|
|
).code,
|
|
{ module: privacyModule, exports: privacyModule.exports }
|
|
)
|
|
const componentPath = path.join(directory, 'CollectionFamilySteps.vue')
|
|
const { descriptor } = parse(fs.readFileSync(componentPath, 'utf8'), { filename: componentPath })
|
|
const script = compileScript(descriptor, { id: 'collection-family-tests' })
|
|
const compiled = esbuild.transformSync(script.content, { loader: 'ts', format: 'cjs' }).code
|
|
|
|
function fixture({ activeStep = 1, readOnly = false, data = {} } = {}) {
|
|
const module = { exports: {} }
|
|
vm.runInNewContext(compiled, {
|
|
module,
|
|
exports: module.exports,
|
|
require: (id) => {
|
|
if (id === 'vue') return vue
|
|
if (id === './collectionFamily') return helpers
|
|
if (id === '@/utils/healthPrivacy') return privacyModule.exports
|
|
throw new Error(`Unexpected import: ${id}`)
|
|
}
|
|
})
|
|
const props = vue.reactive({ activeStep, readOnly, data })
|
|
const scope = vue.effectScope()
|
|
const component = scope.run(() => module.exports.default.setup(props, { expose: () => {} }))
|
|
return { props, component, stop: () => scope.stop() }
|
|
}
|
|
|
|
test('both collection step sections and form fields compile without a nested form', () => {
|
|
const result = compileTemplate({
|
|
source: descriptor.template.content,
|
|
filename: componentPath,
|
|
id: 'collection-family-tests',
|
|
compilerOptions: { bindingMetadata: script.bindings }
|
|
})
|
|
assert.deepEqual(result.errors, [])
|
|
assert.doesNotMatch(descriptor.template.content, /<el-form\s/)
|
|
})
|
|
|
|
test('opening a form does not create a contact until entering step seven', async (t) => {
|
|
const f = fixture()
|
|
t.after(f.stop)
|
|
assert.equal(f.props.data.emergencyContacts, undefined)
|
|
f.props.activeStep = 7
|
|
await vue.nextTick()
|
|
assert.equal(f.props.data.emergencyContacts.length, 1)
|
|
assert.equal(f.props.data.emergencyContacts[0].primary, true)
|
|
assert.equal(f.props.data.emergencyContacts[0].contactOnly, true)
|
|
assert.equal(f.props.data.emergencyContacts[0].relationship, '')
|
|
})
|
|
|
|
test('selecting a priority contact replaces the previous selection and deleting it chooses the remaining first', (t) => {
|
|
const f = fixture({ activeStep: 7 })
|
|
t.after(f.stop)
|
|
f.component.addContact()
|
|
f.component.addContact()
|
|
f.component.primaryIndex.value = 2
|
|
assert.deepEqual(
|
|
Array.from(f.props.data.emergencyContacts, (contact) => contact.primary),
|
|
[false, false, true]
|
|
)
|
|
f.component.removeContact(2)
|
|
assert.deepEqual(
|
|
Array.from(f.props.data.emergencyContacts, (contact) => contact.primary),
|
|
[true, false]
|
|
)
|
|
f.component.removeContact(1)
|
|
f.component.removeContact(0)
|
|
assert.equal(f.component.contacts.value.length, 0)
|
|
f.component.addContact()
|
|
assert.equal(f.component.contacts.value[0].primary, true)
|
|
})
|
|
|
|
test('deleting a non-primary contact preserves the existing choice and stable contact key', (t) => {
|
|
const f = fixture({ activeStep: 7 })
|
|
t.after(f.stop)
|
|
f.component.addContact()
|
|
const second = f.component.contacts.value[1]
|
|
const key = f.component.contactKey(second)
|
|
f.component.primaryIndex.value = 1
|
|
f.component.removeContact(0)
|
|
assert.equal(f.component.contacts.value[0], second)
|
|
assert.equal(second.primary, true)
|
|
assert.equal(f.component.contactKey(second), key)
|
|
})
|
|
|
|
test('adding stops at ten contacts and normalizes multiple or missing priority flags on step seven', (t) => {
|
|
const f = fixture({
|
|
activeStep: 7,
|
|
data: {
|
|
emergencyContacts: [
|
|
helpers.createEmergencyContact(true),
|
|
helpers.createEmergencyContact(true)
|
|
]
|
|
}
|
|
})
|
|
t.after(f.stop)
|
|
for (let index = 0; index < 15; index++) f.component.addContact()
|
|
assert.equal(f.component.contacts.value.length, 10)
|
|
assert.equal(f.component.contacts.value.filter((contact) => contact.primary).length, 1)
|
|
const contacts = [helpers.createEmergencyContact(), helpers.createEmergencyContact()]
|
|
helpers.ensureOnePrimaryContact(contacts)
|
|
assert.equal(contacts[0].primary, true)
|
|
helpers.selectPrimaryContact(contacts, -1)
|
|
helpers.removeEmergencyContact(contacts, 20)
|
|
assert.equal(contacts.length, 2)
|
|
assert.equal(contacts[0].primary, true)
|
|
})
|
|
|
|
test('parent selection clears hidden reasons and detail independently', (t) => {
|
|
const f = fixture({
|
|
data: {
|
|
fatherAlive: 2,
|
|
fatherDeathReason: 4,
|
|
fatherDeathReasonDetail: '父亲原因',
|
|
motherAlive: 2,
|
|
motherDeathReason: 4,
|
|
motherDeathReasonDetail: '母亲原因'
|
|
}
|
|
})
|
|
t.after(f.stop)
|
|
f.component.setParentAlive('father', 3)
|
|
assert.equal(f.props.data.fatherDeathReason, null)
|
|
assert.equal(f.props.data.fatherDeathReasonDetail, null)
|
|
assert.equal(f.props.data.motherDeathReasonDetail, '母亲原因')
|
|
f.component.setParentDeathReason('mother', 2)
|
|
assert.equal(f.props.data.motherDeathReason, 2)
|
|
assert.equal(f.props.data.motherDeathReasonDetail, null)
|
|
f.component.setParentDeathReason('mother', 4)
|
|
f.component.setParentDetail('mother', '新增其他原因')
|
|
assert.equal(f.props.data.motherDeathReasonDetail, '新增其他原因')
|
|
f.component.setParentDeathReason('mother', '')
|
|
assert.equal(f.props.data.motherDeathReason, null)
|
|
assert.equal(f.props.data.motherDeathReasonDetail, null)
|
|
})
|
|
|
|
test('read-only viewing never initializes or changes any fields', async (t) => {
|
|
const data = {
|
|
fatherAlive: 1,
|
|
fatherDeathReason: 4,
|
|
fatherDeathReasonDetail: '历史资料',
|
|
emergencyContacts: [helpers.createEmergencyContact(true), helpers.createEmergencyContact(true)]
|
|
}
|
|
const original = JSON.stringify(data)
|
|
const f = fixture({ activeStep: 7, readOnly: true, data })
|
|
t.after(f.stop)
|
|
f.component.addContact()
|
|
f.component.removeContact(0)
|
|
f.component.primaryIndex.value = 1
|
|
f.component.setParentAlive('father', 2)
|
|
f.component.setParentDeathReason('father', 3)
|
|
f.component.setParentDetail('father', '改动')
|
|
assert.equal(JSON.stringify(f.props.data), original)
|
|
const empty = fixture({ activeStep: 7, readOnly: true })
|
|
t.after(empty.stop)
|
|
assert.equal(empty.props.data.emergencyContacts, undefined)
|
|
f.props.activeStep = 6
|
|
await vue.nextTick()
|
|
assert.equal(JSON.stringify(f.props.data), original)
|
|
})
|