A misconfigured Viya computeTasks deployment makes the Compute service return a plain-text "Job error" body instead of JSON. @sasjs/adapter can't parse it and resolves with that raw text as adapterResponse, so both startup and manual deploy validation reported every expected field as "not present" without ever showing the actual cause. Added getMalformedAdapterResponseMessage to detect a non-object adapterResponse and surface its real text instead.
91 lines
3.5 KiB
TypeScript
91 lines
3.5 KiB
TypeScript
import { ManualComponent } from './manual.component'
|
|
|
|
// validateDeploy() is fire-and-forget (doesn't return its own promise
|
|
// chain), so tests need to wait for it to settle some other way. A
|
|
// macrotask boundary guarantees every already-queued microtask (regardless
|
|
// of how many .then() hops validateDeploy's chain has) has run first.
|
|
const flushPromiseChain = () => new Promise((resolve) => setTimeout(resolve, 0))
|
|
|
|
/**
|
|
* validateDeploy() only touches sasService.request, eventService.showInfoModal
|
|
* and loggerService.log - these stubs cover exactly that surface, not the
|
|
* full real services (no TestBed/DI needed, same plain-instantiation-with-
|
|
* stubs precedent as app.service.spec.ts).
|
|
*/
|
|
const buildDeps = () => {
|
|
const sasService: any = {
|
|
request: jasmine.createSpy('request')
|
|
}
|
|
const eventService: any = {
|
|
showInfoModal: jasmine.createSpy('showInfoModal')
|
|
}
|
|
const loggerService: any = {
|
|
log: jasmine.createSpy('log')
|
|
}
|
|
const deployService: any = {}
|
|
|
|
return { sasService, eventService, loggerService, deployService }
|
|
}
|
|
|
|
const buildManualComponent = (deps: ReturnType<typeof buildDeps>) =>
|
|
new ManualComponent(
|
|
deps.sasService,
|
|
deps.eventService,
|
|
deps.loggerService,
|
|
deps.deployService
|
|
)
|
|
|
|
describe('ManualComponent - validateDeploy', () => {
|
|
it('sets validationState to success when saslibs is present on a normal object response', async () => {
|
|
const deps = buildDeps()
|
|
deps.sasService.request.and.resolveTo({
|
|
adapterResponse: { saslibs: { SOME_LIB: ['SOME_TABLE'] } }
|
|
})
|
|
|
|
const component = buildManualComponent(deps)
|
|
component.validateDeploy()
|
|
await flushPromiseChain()
|
|
|
|
expect(component.validationState).toBe('success')
|
|
expect(deps.eventService.showInfoModal).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('sets validationState to error with no modal when saslibs is missing from an otherwise normal object response', async () => {
|
|
const deps = buildDeps()
|
|
deps.sasService.request.and.resolveTo({
|
|
adapterResponse: { SYSSITE: 'SITE1' }
|
|
// saslibs deliberately omitted
|
|
})
|
|
|
|
const component = buildManualComponent(deps)
|
|
component.validateDeploy()
|
|
await flushPromiseChain()
|
|
|
|
expect(component.validationState).toBe('error')
|
|
expect(deps.eventService.showInfoModal).not.toHaveBeenCalled()
|
|
})
|
|
|
|
// Same underlying bug as app.service.spec.ts's equivalent test: a
|
|
// misconfigured Viya computeTasks deployment returns a raw "Job error"
|
|
// text body, which the adapter resolves as adapterResponse verbatim.
|
|
it('sets validationState to error and shows the real response text when adapterResponse is a raw string, not an object', async () => {
|
|
const deps = buildDeps()
|
|
const rawJobError = [
|
|
'Job error',
|
|
'The Compute service could not execute the task c74a707a-8b88-46a5-8f28-9a7694ad5e13 because the context 340cd3eb-72ae is not reusable. Please provide a reusable context or supply the ID of an existing session in the task request.',
|
|
'path: /compute/tasks',
|
|
'correlator: dc1a9fda-8f65-4f32-b4d4-2a70e02179b1;1bcb6a4c-8a16-4053-a790-292544c25a03'
|
|
].join('\n')
|
|
deps.sasService.request.and.resolveTo({ adapterResponse: rawJobError })
|
|
|
|
const component = buildManualComponent(deps)
|
|
component.validateDeploy()
|
|
await flushPromiseChain()
|
|
|
|
expect(component.validationState).toBe('error')
|
|
expect(deps.eventService.showInfoModal).toHaveBeenCalledTimes(1)
|
|
const [, message] = deps.eventService.showInfoModal.calls.mostRecent().args
|
|
expect(message).toContain(rawJobError)
|
|
})
|
|
})
|