Skip to content

Commit b99106d

Browse files
committed
tests: add several version tests
1 parent 205c964 commit b99106d

3 files changed

Lines changed: 141 additions & 48 deletions

File tree

packages/project/src/util/version.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@ function isDefined(v: any) {
99
return v !== undefined && v !== null;
1010
}
1111

12-
export const workflow = (workflow: Workflow, source = 'cli') => {
12+
export const generateHash = (workflow: Workflow, source = 'cli') => {
1313
const parts = [];
1414

1515
// These are the keys we hash against
1616
const wfKeys = ['name', 'credentials'].sort();
1717
const stepKeys = [
1818
'name',
1919
'adaptors',
20+
'adaptor', // there's ao adaptor & adaptors key in steps somehow.
2021
'expression',
2122
'configuration', // assumes a string credential id
2223
'expression',

packages/project/test/util.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import * as l from '@openfn/lexicon';
88

99
// with metadata or just raw?
1010
// randomise stuff like uuids, name?
11-
export const createWorkflow = (...props: l.Workflow) => ({
11+
export const createWorkflow = (props: l.Workflow) => ({
1212
name: 'wf1',
1313
steps: [
1414
{
Lines changed: 138 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,43 @@
11
import test from 'ava';
22
import { Project } from '../../src/Project';
33
import { createWorkflow } from '../util';
4-
import { workflow } from '../../src/util/version';
4+
import { generateHash } from '../../src/util/version';
5+
import { generateProject, generateWorkflow } from '../../src';
56

67
test('generate an 12 character version hash for a basic workflow', (t) => {
7-
// Keep workflows in lightning state format so that tests are easier to port
8-
const project = {
9-
id: 'p',
10-
workflows: [
11-
{
12-
id: '72ca3eb0-042c-47a0-a2a1-a545ed4a8406',
13-
name: 'a',
14-
edges: [
15-
{
16-
enabled: true,
17-
id: 'a9a3adef-b394-4405-814d-3ac4323f4b4b',
18-
source_trigger_id: '4a06289c-15aa-4662-8dc6-f0aaacd8a058',
19-
condition_type: 'always',
20-
target_job_id: '66add020-e6eb-4eec-836b-20008afca816',
21-
},
22-
],
23-
concurrency: null,
24-
inserted_at: '2025-04-23T11:19:32Z',
25-
updated_at: '2025-04-23T11:19:32Z',
26-
jobs: [
27-
{
28-
id: '66add020-e6eb-4eec-836b-20008afca816',
29-
name: 'Transform data',
30-
body: '// Check out the Job Writing Guide for help getting started:\n// https://docs.openfn.org/documentation/jobs/job-writing-guide\n',
31-
adaptor: '@openfn/language-common@latest',
32-
project_credential_id: null,
33-
},
34-
],
35-
triggers: [
36-
{
37-
enabled: true,
38-
id: '4a06289c-15aa-4662-8dc6-f0aaacd8a058',
39-
type: 'webhook',
40-
},
41-
],
42-
lock_version: 1,
43-
deleted_at: null,
44-
},
45-
],
46-
};
47-
48-
const wf = Project.from('state', project).getWorkflow('a');
49-
50-
const hash = workflow(wf);
8+
const workflow = generateWorkflow(
9+
`
10+
@name a
11+
@id some-id
12+
webhook-transform_data(name="Transform data",expression="// Check out the Job Writing Guide for help getting started:\n// https://docs.openfn.org/documentation/jobs/job-writing-guide\n")
13+
`
14+
);
15+
16+
const hash = generateHash(workflow);
5117
t.log(hash);
52-
t.is(hash, 'cli:fd18866bcb34');
18+
t.is(hash, 'cli:7e5ca7843721');
19+
});
20+
21+
test('unique hash but different steps order', (t) => {
22+
const workflow1 = generateWorkflow(
23+
`
24+
@name same-workflow
25+
@id id-one
26+
a-b
27+
b-c
28+
`
29+
);
30+
const workflow2 = generateWorkflow(
31+
`
32+
@name same-workflow
33+
@id id-two
34+
a-c
35+
c-b
36+
`
37+
);
38+
39+
// different order of nodes (b & c changed position) but should generate the same hash
40+
t.is(generateHash(workflow1), generateHash(workflow2))
5341
});
5442

5543
/**
@@ -61,3 +49,107 @@ test('generate an 12 character version hash for a basic workflow', (t) => {
6149
*
6250
* include a prefix
6351
*/
52+
53+
test('hash changes when workflow name changes', (t) => {
54+
const wf1 = generateWorkflow(
55+
`
56+
@name wf-1
57+
@id workflow-id
58+
a-b
59+
b-c
60+
`
61+
);
62+
const wf2= generateWorkflow(
63+
`
64+
@name wf-2
65+
@id workflow-id
66+
a-b
67+
b-c
68+
`
69+
);
70+
t.not(generateHash(wf1), generateHash(wf2));
71+
});
72+
73+
// can't get credentials to work in the generator, need to fix that
74+
test.skip('hash changes when credentials field changes', (t) => {
75+
const wf1 = generateWorkflow(
76+
`
77+
@name wf-1
78+
@credentials cred-1
79+
@id workflow-id
80+
a-b
81+
b-c
82+
`
83+
);
84+
const wf2 = generateWorkflow(
85+
`
86+
@name wf-1
87+
@credentials cred-2
88+
@id workflow-id
89+
a-b
90+
b-c
91+
`
92+
);
93+
t.not(generateHash(wf1), generateHash(wf2));
94+
});
95+
96+
test("hash changes when a step's adaptor changes", (t) => {
97+
const wf1 = generateWorkflow(
98+
`
99+
@name wf-1
100+
@id workflow-id
101+
a-b(adaptor=http)
102+
b-c
103+
`
104+
);
105+
const wf2 = generateWorkflow(
106+
`
107+
@name wf-1
108+
@id workflow-id
109+
a-b(adaptor=common)
110+
b-c
111+
`
112+
);
113+
t.not(generateHash(wf1), generateHash(wf2));
114+
});
115+
116+
test("hash changes when a step's expression changes", (t) => {
117+
const wf1 = generateWorkflow(
118+
`
119+
@name wf-1
120+
@id workflow-id
121+
a-b
122+
b-c(expression="x=1")
123+
`
124+
);
125+
const wf2 = generateWorkflow(
126+
`
127+
@name wf-1
128+
@id workflow-id
129+
a-b
130+
b-c(expression="x=2")
131+
`
132+
);
133+
t.not(generateHash(wf1), generateHash(wf2));
134+
});
135+
136+
test('ignored fields do not affect hash', (t) => {
137+
const wf1 = generateWorkflow(
138+
`
139+
@name wf-1
140+
@id workflow-id
141+
a-b
142+
b-c(expression="x=1")
143+
`
144+
);
145+
const wf1_ignored = generateWorkflow(
146+
`
147+
@name wf-1
148+
@id workflow-id
149+
@unknownfield some-value
150+
a-b
151+
b-c(expression="x=1")
152+
`
153+
);
154+
t.is(generateHash(wf1), generateHash(wf1_ignored));
155+
});

0 commit comments

Comments
 (0)