11import test from 'ava' ;
22import { Project } from '../../src/Project' ;
33import { createWorkflow } from '../util' ;
4- import { workflow } from '../../src/util/version' ;
4+ import { generateHash } from '../../src/util/version' ;
5+ import { generateProject , generateWorkflow } from '../../src' ;
56
67test ( '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