Changeset 0.30.2 cs2 (#202)
Co-authored-by: Jeffrey Smith <jasafpro@gmail.com> Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
This commit is contained in:
@@ -599,5 +599,140 @@
|
||||
})();
|
||||
}
|
||||
|
||||
// ── Workflow Package Export/Import (v0.30.2) ──
|
||||
if (T.user.role === 'admin') {
|
||||
await (async function () {
|
||||
var wpWfId = null;
|
||||
var wpStage1Id = null;
|
||||
var wpStage2Id = null;
|
||||
var wpPkgId = null;
|
||||
var wpSlug = testTag.toLowerCase().replace(/[^a-z0-9-]/g, '-') + '-wp';
|
||||
|
||||
await T.test('crud', 'workflows', 'wfpkg: create workflow for export', async function () {
|
||||
var d = await T.apiPost('/workflows', {
|
||||
name: testTag + '-wfpkg',
|
||||
slug: wpSlug,
|
||||
description: 'Workflow package export/import test',
|
||||
entry_mode: 'public_link'
|
||||
});
|
||||
T.assertShape(d, T.S.workflow, 'workflow');
|
||||
wpWfId = d.id;
|
||||
T.registerCleanup(function () {
|
||||
if (wpWfId) return T.safeDelete('/workflows/' + wpWfId);
|
||||
});
|
||||
});
|
||||
|
||||
if (wpWfId) {
|
||||
await T.test('crud', 'workflows', 'wfpkg: add stages with form_template', async function () {
|
||||
var s1 = await T.apiPost('/workflows/' + wpWfId + '/stages', {
|
||||
name: 'Intake',
|
||||
ordinal: 0,
|
||||
stage_mode: 'form_only',
|
||||
history_mode: 'full',
|
||||
form_template: { fields: [{ key: 'name', type: 'text', label: 'Full Name', required: true }] }
|
||||
});
|
||||
T.assertShape(s1, T.S.workflowStage, 'stage1');
|
||||
wpStage1Id = s1.id;
|
||||
|
||||
var s2 = await T.apiPost('/workflows/' + wpWfId + '/stages', {
|
||||
name: 'Review',
|
||||
ordinal: 1,
|
||||
stage_mode: 'review',
|
||||
history_mode: 'summary'
|
||||
});
|
||||
T.assertShape(s2, T.S.workflowStage, 'stage2');
|
||||
wpStage2Id = s2.id;
|
||||
});
|
||||
|
||||
// Test surface_pkg_id round-trip
|
||||
await T.test('crud', 'workflows', 'wfpkg: surface_pkg_id persists on update', async function () {
|
||||
// Stage update is PUT (full replace), so send all required fields.
|
||||
// Use the ICD test runner's own package ID (always installed when tests run).
|
||||
var realPkgId = 'icd-test-runner';
|
||||
var stageBase = {
|
||||
name: 'Intake', ordinal: 0, stage_mode: 'form_only', history_mode: 'full',
|
||||
form_template: { fields: [{ key: 'name', type: 'text', label: 'Full Name', required: true }] }
|
||||
};
|
||||
|
||||
// Set surface_pkg_id
|
||||
var withPkg = Object.assign({}, stageBase, { surface_pkg_id: realPkgId });
|
||||
var updated = await T.apiPut('/workflows/' + wpWfId + '/stages/' + wpStage1Id, withPkg);
|
||||
T.assert(updated.surface_pkg_id === realPkgId,
|
||||
'surface_pkg_id should persist, got: ' + updated.surface_pkg_id);
|
||||
|
||||
// Clear it
|
||||
var cleared = await T.apiPut('/workflows/' + wpWfId + '/stages/' + wpStage1Id, stageBase);
|
||||
T.assert(!cleared.surface_pkg_id,
|
||||
'surface_pkg_id should be cleared, got: ' + cleared.surface_pkg_id);
|
||||
});
|
||||
|
||||
// Export workflow as .pkg
|
||||
var exportBlob = null;
|
||||
await T.test('crud', 'workflows', 'wfpkg: GET export .pkg', async function () {
|
||||
var token = await T.getAuthToken();
|
||||
var resp = await fetch(T.base + '/api/v1/admin/workflows/' + wpWfId + '/export', {
|
||||
headers: { 'Authorization': 'Bearer ' + token }
|
||||
});
|
||||
T.assert(resp.ok, 'export should return 200, got ' + resp.status);
|
||||
var ct = resp.headers.get('content-type') || '';
|
||||
T.assert(ct.indexOf('zip') !== -1 || ct.indexOf('octet') !== -1,
|
||||
'content-type should be zip/octet, got ' + ct);
|
||||
exportBlob = await resp.blob();
|
||||
T.assert(exportBlob.size > 0, 'export blob should not be empty');
|
||||
});
|
||||
|
||||
// Delete original workflow before import to test clean install
|
||||
await T.test('crud', 'workflows', 'wfpkg: delete original workflow', async function () {
|
||||
await T.apiDelete('/workflows/' + wpWfId);
|
||||
wpWfId = null;
|
||||
});
|
||||
|
||||
// Import the .pkg
|
||||
if (exportBlob) {
|
||||
await T.test('crud', 'workflows', 'wfpkg: POST install .pkg (re-import)', async function () {
|
||||
var token = await T.getAuthToken();
|
||||
var formData = new FormData();
|
||||
formData.append('file', exportBlob, 'test-workflow.pkg');
|
||||
var resp = await fetch(T.base + '/api/v1/admin/packages/install', {
|
||||
method: 'POST',
|
||||
headers: { 'Authorization': 'Bearer ' + token },
|
||||
body: formData
|
||||
});
|
||||
var result = await resp.json();
|
||||
T.assert(resp.ok, 'install should return 200, got ' + resp.status + ': ' + (result.error || ''));
|
||||
T.assert(result.id, 'install should return package id');
|
||||
wpPkgId = result.id;
|
||||
T.registerCleanup(function () {
|
||||
if (wpPkgId) return T.safeDelete('/admin/packages/' + wpPkgId);
|
||||
});
|
||||
});
|
||||
|
||||
// Verify the workflow was recreated
|
||||
await T.test('crud', 'workflows', 'wfpkg: verify imported workflow has stages', async function () {
|
||||
var wfs = await T.apiGet('/workflows');
|
||||
var list = wfs.data || wfs || [];
|
||||
var found = list.find(function (w) { return w.slug === wpSlug; });
|
||||
T.assert(found, 'imported workflow with slug ' + wpSlug + ' should exist');
|
||||
wpWfId = found.id;
|
||||
|
||||
var stages = await T.apiGet('/workflows/' + wpWfId + '/stages');
|
||||
var stList = stages.data || stages || [];
|
||||
T.assert(stList.length === 2, 'should have 2 stages, got ' + stList.length);
|
||||
T.assert(stList[0].name === 'Intake', 'stage 0 name should be Intake');
|
||||
T.assert(stList[1].name === 'Review', 'stage 1 name should be Review');
|
||||
T.assert(stList[0].stage_mode === 'form_only', 'stage 0 mode should be form_only');
|
||||
T.assert(stList[1].stage_mode === 'review', 'stage 1 mode should be review');
|
||||
});
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
await T.test('crud', 'workflows', 'wfpkg: cleanup', async function () {
|
||||
if (wpPkgId) { await T.safeDelete('/admin/packages/' + wpPkgId); wpPkgId = null; }
|
||||
if (wpWfId) { await T.safeDelete('/workflows/' + wpWfId); wpWfId = null; }
|
||||
});
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
};
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user