create-auto-app 0.9.11 → 0.9.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +12 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +98 -19
- package/dist/index.js.map +1 -1
- package/dist/index.specs.d.ts +2 -0
- package/dist/index.specs.d.ts.map +1 -0
- package/dist/index.specs.js +267 -0
- package/dist/index.specs.js.map +1 -0
- package/package.json +7 -4
- package/templates/finance-app/.context/design-system.md +142 -0
- package/templates/finance-app/.context/figma-variables.json +13759 -0
- package/templates/finance-app/.context/shadcn-filter.ts +29 -0
- package/templates/finance-app/auto.config.ts +180 -0
- package/templates/finance-app/flows/app-homepage.flow.ts +84 -0
- package/templates/finance-app/flows/landing-page.flow.ts +34 -0
- package/templates/finance-app/package.json +30 -0
- package/templates/finance-app/pnpm-lock.yaml +12518 -0
- package/templates/finance-app/pnpm-workspace.yaml +2 -0
- package/templates/finance-app/tsconfig.base.json +17 -0
- package/templates/finance-app/tsconfig.json +17 -0
- package/templates/finance-app/turbo.json +19 -0
- package/templates/questionnaires/auto.config.ts +158 -0
- package/templates/questionnaires/flows/questionnaires.flow.ts +359 -0
- package/templates/questionnaires/package.json +30 -0
- package/templates/questionnaires/template.json +7 -0
- package/templates/questionnaires/tsconfig.json +15 -0
- package/templates/shopping-app/auto.config.ts +2 -0
- package/templates/shopping-app/template.json +7 -0
- package/templates/.gitkeep +0 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"emitDecoratorMetadata": true,
|
|
8
|
+
"experimentalDecorators": true,
|
|
9
|
+
"outDir": "./dist",
|
|
10
|
+
"rootDir": ".",
|
|
11
|
+
"noEmit": false,
|
|
12
|
+
"strict": true,
|
|
13
|
+
"strictNullChecks": true
|
|
14
|
+
},
|
|
15
|
+
"include": ["flows/**/*", "vitest.config.ts"],
|
|
16
|
+
"exclude": ["dist", "node_modules"]
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"emitDecoratorMetadata": true,
|
|
8
|
+
"experimentalDecorators": true,
|
|
9
|
+
"outDir": "./dist",
|
|
10
|
+
"rootDir": ".",
|
|
11
|
+
"noEmit": false,
|
|
12
|
+
"strict": true,
|
|
13
|
+
"strictNullChecks": true
|
|
14
|
+
},
|
|
15
|
+
"include": ["flows/**/*", "vitest.config.ts"],
|
|
16
|
+
"exclude": ["dist", "node_modules"]
|
|
17
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://turbo.build/schema.json",
|
|
3
|
+
"extends": ["//"],
|
|
4
|
+
"tasks": {
|
|
5
|
+
"auto": {
|
|
6
|
+
"dependsOn": ["^build"],
|
|
7
|
+
"inputs": []
|
|
8
|
+
},
|
|
9
|
+
"auto:debug": {
|
|
10
|
+
"dependsOn": ["^build"],
|
|
11
|
+
"inputs": []
|
|
12
|
+
},
|
|
13
|
+
"build": {
|
|
14
|
+
"dependsOn": ["^build"],
|
|
15
|
+
"inputs": [],
|
|
16
|
+
"outputs": []
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { autoConfig, on, dispatch } from '@auto-engineer/cli';
|
|
2
|
+
import type { ExportSchemaCommand, ExportSchemaEvents } from '@auto-engineer/flow';
|
|
3
|
+
import type { GenerateServerCommand, GenerateServerEvents } from '@auto-engineer/server-generator-apollo-emmett';
|
|
4
|
+
import type { ImplementServerCommand, ImplementServerEvents } from '@auto-engineer/server-implementer';
|
|
5
|
+
import type {
|
|
6
|
+
CheckTestsCommand,
|
|
7
|
+
CheckTestsEvents,
|
|
8
|
+
CheckTypesCommand,
|
|
9
|
+
CheckTypesEvents,
|
|
10
|
+
CheckLintCommand,
|
|
11
|
+
CheckLintEvents,
|
|
12
|
+
TestsCheckFailedEvent,
|
|
13
|
+
} from '@auto-engineer/server-checks';
|
|
14
|
+
import type { GenerateIACommand, GenerateIAEvents } from '@auto-engineer/information-architect';
|
|
15
|
+
import type { ImplementClientCommand, ImplementClientEvents } from '@auto-engineer/frontend-implementer';
|
|
16
|
+
import type { GenerateClientCommand, GenerateClientEvents } from '@auto-engineer/frontend-generator-react-graphql';
|
|
17
|
+
|
|
18
|
+
export default autoConfig({
|
|
19
|
+
fileId: 'test2222', // unique 9-character base62 canvas file id where all flows in this project will be shown
|
|
20
|
+
|
|
21
|
+
plugins: [
|
|
22
|
+
'@auto-engineer/server-checks',
|
|
23
|
+
'@auto-engineer/design-system-importer',
|
|
24
|
+
'@auto-engineer/server-generator-apollo-emmett',
|
|
25
|
+
'@auto-engineer/flow',
|
|
26
|
+
'@auto-engineer/frontend-checks',
|
|
27
|
+
'@auto-engineer/frontend-implementer',
|
|
28
|
+
'@auto-engineer/information-architect',
|
|
29
|
+
'@auto-engineer/frontend-generator-react-graphql',
|
|
30
|
+
'@auto-engineer/server-implementer',
|
|
31
|
+
],
|
|
32
|
+
aliases: {
|
|
33
|
+
// Resolve command name conflicts between packages
|
|
34
|
+
// 'test:types': checkTypesCommandHandler,
|
|
35
|
+
},
|
|
36
|
+
pipeline: () => {
|
|
37
|
+
on<ExportSchemaEvents>('SchemaExported', () =>
|
|
38
|
+
dispatch<GenerateServerCommand>('GenerateServer', {
|
|
39
|
+
schemaPath: './.context/schema.json',
|
|
40
|
+
destination: '.',
|
|
41
|
+
}),
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
on<GenerateServerEvents>('ServerGenerated', () =>
|
|
45
|
+
dispatch<GenerateIACommand>('GenerateIA', {
|
|
46
|
+
outputDir: './.context',
|
|
47
|
+
flowFiles: ['./flows/questionnaires.flow.ts'],
|
|
48
|
+
}),
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
on<GenerateIAEvents>('IAGenerated', () =>
|
|
52
|
+
dispatch<GenerateClientCommand>('GenerateClient', {
|
|
53
|
+
starterDir: '../../packages/frontend-generator-react-graphql/shadcn-starter',
|
|
54
|
+
targetDir: './client',
|
|
55
|
+
iaSchemaPath: './.context/auto-ia-scheme.json',
|
|
56
|
+
gqlSchemaPath: './.context/schema.graphql',
|
|
57
|
+
figmaVariablesPath: './.context/figma-variables.json',
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
on<GenerateClientEvents>('ClientGenerated', () =>
|
|
62
|
+
dispatch<ImplementClientCommand>('ImplementClient', {
|
|
63
|
+
projectDir: './client',
|
|
64
|
+
iaSchemeDir: './.context',
|
|
65
|
+
designSystemPath: './.context/design-system.md',
|
|
66
|
+
}),
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
on<ImplementServerEvents>('SliceImplemented', () => {
|
|
70
|
+
dispatch<CheckTestsCommand>('CheckTests', {
|
|
71
|
+
targetDirectory: 'sds',
|
|
72
|
+
scope: 'slice',
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
on<ImplementServerEvents>('SliceImplemented', () => {
|
|
77
|
+
dispatch<CheckTypesCommand>('CheckTypes', {
|
|
78
|
+
targetDirectory: 'sds',
|
|
79
|
+
scope: 'slice',
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
on<ImplementServerEvents>('SliceImplemented', () => {
|
|
84
|
+
dispatch<CheckLintCommand>('CheckLint', {
|
|
85
|
+
targetDirectory: 'sds',
|
|
86
|
+
scope: 'slice',
|
|
87
|
+
fix: true,
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
on.settled<CheckTestsCommand, CheckTypesCommand, CheckLintCommand>(
|
|
92
|
+
['CheckTests', 'CheckTypes', 'CheckLint'],
|
|
93
|
+
dispatch<ImplementClientCommand>(['ImplementClient'], (events, send) => {
|
|
94
|
+
const hasFailures =
|
|
95
|
+
events.CheckTests.some((e: CheckTestsEvents) => e.type === 'TestsCheckFailed') ||
|
|
96
|
+
events.CheckTypes.some((e: CheckTypesEvents) => e.type === 'TypeCheckFailed') ||
|
|
97
|
+
events.CheckLint.some((e: CheckLintEvents) => e.type === 'LintCheckFailed');
|
|
98
|
+
|
|
99
|
+
if (hasFailures) {
|
|
100
|
+
send({
|
|
101
|
+
type: 'ImplementClient',
|
|
102
|
+
data: {
|
|
103
|
+
projectDir: 'some/where',
|
|
104
|
+
iaSchemeDir: '/',
|
|
105
|
+
designSystemPath: '',
|
|
106
|
+
failures: [],
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}),
|
|
111
|
+
);
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
/*
|
|
115
|
+
|
|
116
|
+
rm -rf server client .context/schema.json .context/schema.graphql .context/auto-ia-scheme.json
|
|
117
|
+
pnpm auto export:schema
|
|
118
|
+
pnpm auto generate:ia --output-dir=./.context --flow-files=./flows/questionnaires.flow.ts
|
|
119
|
+
pnpm auto generate:server --schema-path=./.context/schema.json --destination=.
|
|
120
|
+
pnpm auto generate:client --starter-dir=../../packages/frontend-generator-react-graphql/shadcn-starter --target-dir=./client --ia-schema-path=./.context/auto-ia-scheme.json --gql-schema-path=./.context/schema.graphql --figma-variables-path=./.context/figma-variables.json
|
|
121
|
+
pnpm auto implement:client --project-dir=./questionnaires/client --ia-scheme-dir=./questionnaires/.context --design-system-path=./questionnaires/.context/design-system.md
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
// make this emit one slice at a time
|
|
125
|
+
pnpm auto generate:server --schema-path=./.context/schema.json --destination=.
|
|
126
|
+
|
|
127
|
+
// TODO remove the AI part and make it mathematical
|
|
128
|
+
pnpm auto generate:client --starter-dir=/Users/sam/WebstormProjects/top/auto-engineer/packages/frontend-generator-react-graphql/shadcn-starter --target-dir=./client --ia-schema-path=./.context/auto-ia-scheme.json --gql-schema-path=./.context/schema.graphql --figma-variables-path=./.context/figma-variables.json
|
|
129
|
+
|
|
130
|
+
// run this per slice in parallel
|
|
131
|
+
pnpm auto implement:slice --slice-path=./questionnaires/server/src/domain/flows/questionnaires/submits-the-questionnaire
|
|
132
|
+
// add checks
|
|
133
|
+
// add retry logic tore-implement failed slices with a retry count
|
|
134
|
+
|
|
135
|
+
// slice these up
|
|
136
|
+
pnpm auto implement:client --project-dir=./questionnaires/client --ia-scheme-dir=./questionnaires/.context --design-system-path=./questionnaires/.context/design-system.md
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
// implement atoms in parallel - how do I know all atoms are done?
|
|
140
|
+
// implement molecules in parallel - how do I know all molecules are done?
|
|
141
|
+
// implement organisms in parallel - how do I know all organisms are done?
|
|
142
|
+
// implement pages in parallel - how do I know all pages are done?
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
// generate slice > implement slice > check slice > retry failure 3 times >
|
|
146
|
+
// generate slice > implement slice > check slice > retry failure 3 times >
|
|
147
|
+
// generate slice > implement slice > check slice > retry failure 3 times >
|
|
148
|
+
|
|
149
|
+
cd ~/WebstormProjects/top/auto-engineer/examples/questionnaires &&\
|
|
150
|
+
pnpm -w build &&\
|
|
151
|
+
rm -rf server client .context/schema.json .context/schema.graphql .context/auto-ia-scheme.json &&\
|
|
152
|
+
DEBUG=* pnpm auto export:schema &&\
|
|
153
|
+
DEBUG=* pnpm auto generate:server --schema-path=./.context/schema.json --destination=. &&\
|
|
154
|
+
DEBUG=* pnpm auto generate:ia --output-dir=./.context --flow-files=./flows/questionnaires.flow.ts &&\
|
|
155
|
+
DEBUG=* pnpm auto generate:client --starter-dir=../../packages/frontend-generator-react-graphql/shadcn-starter --target-dir=./client --ia-schema-path=./.context/auto-ia-scheme.json --gql-schema-path=./.context/schema.graphql --figma-variables-path=./.context/figma-variables.json
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
*/
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import {
|
|
2
|
+
command,
|
|
3
|
+
query,
|
|
4
|
+
experience,
|
|
5
|
+
flow,
|
|
6
|
+
should,
|
|
7
|
+
specs,
|
|
8
|
+
rule,
|
|
9
|
+
example,
|
|
10
|
+
gql,
|
|
11
|
+
source,
|
|
12
|
+
data,
|
|
13
|
+
sink,
|
|
14
|
+
type Command,
|
|
15
|
+
type Event,
|
|
16
|
+
type State,
|
|
17
|
+
} from '@auto-engineer/flow';
|
|
18
|
+
|
|
19
|
+
type QuestionnaireLinkSent = Event<
|
|
20
|
+
'QuestionnaireLinkSent',
|
|
21
|
+
{
|
|
22
|
+
questionnaireId: string;
|
|
23
|
+
participantId: string;
|
|
24
|
+
link: string;
|
|
25
|
+
sentAt: Date;
|
|
26
|
+
}
|
|
27
|
+
>;
|
|
28
|
+
|
|
29
|
+
type QuestionAnswered = Event<
|
|
30
|
+
'QuestionAnswered',
|
|
31
|
+
{
|
|
32
|
+
questionnaireId: string;
|
|
33
|
+
participantId: string;
|
|
34
|
+
questionId: string;
|
|
35
|
+
answer: unknown;
|
|
36
|
+
savedAt: Date;
|
|
37
|
+
}
|
|
38
|
+
>;
|
|
39
|
+
|
|
40
|
+
type QuestionnaireSubmitted = Event<
|
|
41
|
+
'QuestionnaireSubmitted',
|
|
42
|
+
{
|
|
43
|
+
questionnaireId: string;
|
|
44
|
+
participantId: string;
|
|
45
|
+
submittedAt: Date;
|
|
46
|
+
}
|
|
47
|
+
>;
|
|
48
|
+
|
|
49
|
+
type QuestionnaireEditRejected = Event<
|
|
50
|
+
'QuestionnaireEditRejected',
|
|
51
|
+
{
|
|
52
|
+
questionnaireId: string;
|
|
53
|
+
participantId: string;
|
|
54
|
+
reason: string;
|
|
55
|
+
attemptedAt: Date;
|
|
56
|
+
}
|
|
57
|
+
>;
|
|
58
|
+
|
|
59
|
+
type AnswerQuestion = Command<
|
|
60
|
+
'AnswerQuestion',
|
|
61
|
+
{
|
|
62
|
+
questionnaireId: string;
|
|
63
|
+
participantId: string;
|
|
64
|
+
questionId: string;
|
|
65
|
+
answer: unknown;
|
|
66
|
+
}
|
|
67
|
+
>;
|
|
68
|
+
|
|
69
|
+
type SubmitQuestionnaire = Command<
|
|
70
|
+
'SubmitQuestionnaire',
|
|
71
|
+
{
|
|
72
|
+
questionnaireId: string;
|
|
73
|
+
participantId: string;
|
|
74
|
+
}
|
|
75
|
+
>;
|
|
76
|
+
|
|
77
|
+
type QuestionnaireConfig = State<
|
|
78
|
+
'QuestionnaireConfig',
|
|
79
|
+
{
|
|
80
|
+
questionnaireId: string;
|
|
81
|
+
numberOfQuestions: number;
|
|
82
|
+
}
|
|
83
|
+
>;
|
|
84
|
+
|
|
85
|
+
type QuestionnaireProgress = State<
|
|
86
|
+
'QuestionnaireProgress',
|
|
87
|
+
{
|
|
88
|
+
questionnaireId: string;
|
|
89
|
+
participantId: string;
|
|
90
|
+
status: 'in_progress' | 'ready_to_submit' | 'submitted';
|
|
91
|
+
currentQuestionId: string | null;
|
|
92
|
+
remainingQuestions: string[];
|
|
93
|
+
answers: { questionId: string; value: unknown }[];
|
|
94
|
+
}
|
|
95
|
+
>;
|
|
96
|
+
|
|
97
|
+
flow('Questionnaires', 'AUTO-Q9m2Kp4Lx', () => {
|
|
98
|
+
experience('Homepage', 'AUTO-H1a4Bn6Cy').client(() => {
|
|
99
|
+
specs(() => {
|
|
100
|
+
should('show a hero section with a welcome message');
|
|
101
|
+
should('allow user to start the questionnaire');
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
query('views the questionnaire', 'AUTO-V7n8Rq5M')
|
|
106
|
+
.server(() => {
|
|
107
|
+
specs(() => {
|
|
108
|
+
rule('questionnaires show current progress', 'AUTO-r1A3Bp9W', () => {
|
|
109
|
+
example('a question has already been answered')
|
|
110
|
+
.given<QuestionnaireLinkSent>({
|
|
111
|
+
questionnaireId: 'q-001',
|
|
112
|
+
participantId: 'participant-abc',
|
|
113
|
+
link: 'https://app.example.com/q/q-001?participant=participant-abc',
|
|
114
|
+
sentAt: new Date('2030-01-01T09:00:00Z'),
|
|
115
|
+
})
|
|
116
|
+
.when<QuestionAnswered>({
|
|
117
|
+
questionnaireId: 'q-001',
|
|
118
|
+
participantId: 'participant-abc',
|
|
119
|
+
questionId: 'q1',
|
|
120
|
+
answer: 'Yes',
|
|
121
|
+
savedAt: new Date('2030-01-01T09:05:00Z'),
|
|
122
|
+
})
|
|
123
|
+
.then<QuestionnaireProgress>({
|
|
124
|
+
questionnaireId: 'q-001',
|
|
125
|
+
participantId: 'participant-abc',
|
|
126
|
+
status: 'in_progress',
|
|
127
|
+
currentQuestionId: 'q2',
|
|
128
|
+
remainingQuestions: ['q2', 'q3'],
|
|
129
|
+
answers: [{ questionId: 'q1', value: 'Yes' }],
|
|
130
|
+
});
|
|
131
|
+
example('no questions have been answered yet')
|
|
132
|
+
.given<QuestionnaireLinkSent>({
|
|
133
|
+
questionnaireId: 'q-001',
|
|
134
|
+
participantId: 'participant-abc',
|
|
135
|
+
link: 'https://app.example.com/q/q-001?participant=participant-abc',
|
|
136
|
+
sentAt: new Date('2030-01-01T09:00:00Z'),
|
|
137
|
+
})
|
|
138
|
+
.when({})
|
|
139
|
+
.then<QuestionnaireProgress>({
|
|
140
|
+
questionnaireId: 'q-001',
|
|
141
|
+
participantId: 'participant-abc',
|
|
142
|
+
status: 'in_progress',
|
|
143
|
+
currentQuestionId: 'q1',
|
|
144
|
+
remainingQuestions: ['q1', 'q2', 'q3'],
|
|
145
|
+
answers: [],
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
data([source().state('QuestionnaireProgress').fromProjection('Questionnaires', 'questionnaire-participantId')]);
|
|
150
|
+
})
|
|
151
|
+
.request(gql`
|
|
152
|
+
query QuestionnaireProgress($participantId: ID!) {
|
|
153
|
+
questionnaireProgress(participantId: $participantId) {
|
|
154
|
+
questionnaireId
|
|
155
|
+
participantId
|
|
156
|
+
currentQuestionId
|
|
157
|
+
remainingQuestions
|
|
158
|
+
status
|
|
159
|
+
answers {
|
|
160
|
+
questionId
|
|
161
|
+
value
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
`)
|
|
166
|
+
.client(() => {
|
|
167
|
+
specs('Questionnaire Progress', () => {
|
|
168
|
+
should('focus on the current question based on the progress state');
|
|
169
|
+
should('display the list of answered questions');
|
|
170
|
+
should('display the list of remaining questions');
|
|
171
|
+
should('show a progress indicator that is always visible as the user scrolls');
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
command('submits a questionnaire answer', 'AUTO-S4j6Nt8Z')
|
|
176
|
+
.server(() => {
|
|
177
|
+
specs(() => {
|
|
178
|
+
rule('answers are allowed while the questionnaire has not been submitted', 'AUTO-r2D5Eq0Y', () => {
|
|
179
|
+
example('no questions have been answered yet')
|
|
180
|
+
.when<AnswerQuestion>({
|
|
181
|
+
questionnaireId: 'q-001',
|
|
182
|
+
participantId: 'participant-abc',
|
|
183
|
+
questionId: 'q1',
|
|
184
|
+
answer: 'Yes',
|
|
185
|
+
})
|
|
186
|
+
.then<QuestionAnswered>({
|
|
187
|
+
questionnaireId: 'q-001',
|
|
188
|
+
participantId: 'participant-abc',
|
|
189
|
+
questionId: 'q1',
|
|
190
|
+
answer: 'Yes',
|
|
191
|
+
savedAt: new Date('2030-01-01T09:05:00Z'),
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
example('all questions have already been answered and submitted')
|
|
195
|
+
.given<QuestionnaireSubmitted>({
|
|
196
|
+
questionnaireId: 'q-001',
|
|
197
|
+
participantId: 'participant-abc',
|
|
198
|
+
submittedAt: new Date('2030-01-01T09:00:00Z'),
|
|
199
|
+
})
|
|
200
|
+
.when<AnswerQuestion>({
|
|
201
|
+
questionnaireId: 'q-001',
|
|
202
|
+
participantId: 'participant-abc',
|
|
203
|
+
questionId: 'q1',
|
|
204
|
+
answer: 'Yes',
|
|
205
|
+
})
|
|
206
|
+
.then<QuestionnaireEditRejected>({
|
|
207
|
+
questionnaireId: 'q-001',
|
|
208
|
+
participantId: 'participant-abc',
|
|
209
|
+
reason: 'Questionnaire already submitted',
|
|
210
|
+
attemptedAt: new Date('2030-01-01T09:05:00Z'),
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
data([
|
|
215
|
+
sink().event('QuestionAnswered').toStream('questionnaire-participantId'),
|
|
216
|
+
sink().event('QuestionnaireEditRejected').toStream('questionnaire-participantId'),
|
|
217
|
+
]);
|
|
218
|
+
})
|
|
219
|
+
.request(gql`
|
|
220
|
+
mutation AnswerQuestion($input: AnswerQuestionInput!) {
|
|
221
|
+
answerQuestion(input: $input) {
|
|
222
|
+
success
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
`)
|
|
226
|
+
.client(() => {
|
|
227
|
+
specs('Submissions', () => {
|
|
228
|
+
should('displays a success message when the answer is submitted');
|
|
229
|
+
should('display an error message when the answer submission is rejected');
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
query('questionnaire ready for submission', 'AUTO-R3f7Hu1X')
|
|
234
|
+
.server(() => {
|
|
235
|
+
specs(() => {
|
|
236
|
+
rule('questionnaire is ready for submission when all questions are answered', 'AUTO-r3G8Iv2W', () => {
|
|
237
|
+
example('all questions have been answered')
|
|
238
|
+
.given<QuestionnaireConfig>({
|
|
239
|
+
questionnaireId: 'q-001',
|
|
240
|
+
numberOfQuestions: 2,
|
|
241
|
+
})
|
|
242
|
+
.and<QuestionnaireLinkSent>({
|
|
243
|
+
questionnaireId: 'q-001',
|
|
244
|
+
participantId: 'participant-abc',
|
|
245
|
+
link: 'https://app.example.com/q/q-001?participant=participant-abc',
|
|
246
|
+
sentAt: new Date('2030-01-01T09:00:00Z'),
|
|
247
|
+
})
|
|
248
|
+
.and<QuestionAnswered>({
|
|
249
|
+
questionnaireId: 'q-001',
|
|
250
|
+
participantId: 'participant-abc',
|
|
251
|
+
questionId: 'q1',
|
|
252
|
+
answer: 'Yes',
|
|
253
|
+
savedAt: new Date('2030-01-01T09:05:00Z'),
|
|
254
|
+
})
|
|
255
|
+
.and<QuestionAnswered>({
|
|
256
|
+
questionnaireId: 'q-001',
|
|
257
|
+
participantId: 'participant-abc',
|
|
258
|
+
questionId: 'q2',
|
|
259
|
+
answer: 'No',
|
|
260
|
+
savedAt: new Date('2030-01-01T09:05:00Z'),
|
|
261
|
+
})
|
|
262
|
+
.when({}) // FIX ME
|
|
263
|
+
.then<QuestionnaireProgress>({
|
|
264
|
+
questionnaireId: 'q-001',
|
|
265
|
+
participantId: 'participant-abc',
|
|
266
|
+
status: 'ready_to_submit',
|
|
267
|
+
currentQuestionId: null,
|
|
268
|
+
remainingQuestions: [],
|
|
269
|
+
answers: [
|
|
270
|
+
{ questionId: 'q1', value: 'Yes' },
|
|
271
|
+
{ questionId: 'q2', value: 'No' },
|
|
272
|
+
],
|
|
273
|
+
});
|
|
274
|
+
example('some questions are still unanswered')
|
|
275
|
+
.given<QuestionnaireLinkSent>({
|
|
276
|
+
questionnaireId: 'q-001',
|
|
277
|
+
participantId: 'participant-abc',
|
|
278
|
+
link: 'https://app.example.com/q/q-001?participant=participant-abc',
|
|
279
|
+
sentAt: new Date('2030-01-01T09:00:00Z'),
|
|
280
|
+
})
|
|
281
|
+
.when<QuestionAnswered>({
|
|
282
|
+
questionnaireId: 'q-001',
|
|
283
|
+
participantId: 'participant-abc',
|
|
284
|
+
questionId: 'q1',
|
|
285
|
+
answer: 'Yes',
|
|
286
|
+
savedAt: new Date('2030-01-01T09:05:00Z'),
|
|
287
|
+
})
|
|
288
|
+
.then<QuestionnaireProgress>({
|
|
289
|
+
questionnaireId: 'q-001',
|
|
290
|
+
participantId: 'participant-abc',
|
|
291
|
+
status: 'in_progress',
|
|
292
|
+
currentQuestionId: 'q2',
|
|
293
|
+
remainingQuestions: ['q2', 'q3'],
|
|
294
|
+
answers: [{ questionId: 'q1', value: 'Yes' }],
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
data([
|
|
299
|
+
source().state('QuestionnaireProgress').fromProjection('Questionnaires', 'questionnaire-participantId'),
|
|
300
|
+
source().state('QuestionnaireConfig').fromDatabase('QuestionnaireConfigAPI'),
|
|
301
|
+
]);
|
|
302
|
+
})
|
|
303
|
+
.request(gql`
|
|
304
|
+
query QuestionnaireProgress($participantId: ID!) {
|
|
305
|
+
questionnaireProgress(participantId: $participantId) {
|
|
306
|
+
questionnaireId
|
|
307
|
+
participantId
|
|
308
|
+
status
|
|
309
|
+
currentQuestionId
|
|
310
|
+
remainingQuestions
|
|
311
|
+
answers {
|
|
312
|
+
questionId
|
|
313
|
+
value
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
`)
|
|
318
|
+
.client(() => {
|
|
319
|
+
specs('Submission Readiness', () => {
|
|
320
|
+
should('enable the submit button when all questions are answered');
|
|
321
|
+
should('disable the submit button when all questions have not been answered');
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
command('submits the questionnaire', 'AUTO-T5k9Jw3V')
|
|
326
|
+
.server(() => {
|
|
327
|
+
specs(() => {
|
|
328
|
+
rule('questionnaire allowed to be submitted when all questions are answered', 'AUTO-r4H0Lx4U', () => {
|
|
329
|
+
example('submits the questionnaire successfully')
|
|
330
|
+
.when<SubmitQuestionnaire>({
|
|
331
|
+
questionnaireId: 'q-001',
|
|
332
|
+
participantId: 'participant-abc',
|
|
333
|
+
})
|
|
334
|
+
.then<QuestionnaireSubmitted>({
|
|
335
|
+
questionnaireId: 'q-001',
|
|
336
|
+
participantId: 'participant-abc',
|
|
337
|
+
submittedAt: new Date('2030-01-01T09:00:00Z'),
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
data([sink().event('QuestionnaireSubmitted').toStream('questionnaire-participantId')]);
|
|
342
|
+
})
|
|
343
|
+
.request(gql`
|
|
344
|
+
mutation SubmitQuestionnaire($input: SubmitQuestionnaireInput!) {
|
|
345
|
+
submitQuestionnaire(input: $input) {
|
|
346
|
+
success
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
`)
|
|
350
|
+
.client(() => {
|
|
351
|
+
specs('Submission Confirmation', () => {
|
|
352
|
+
should('display a confirmation message upon successful submission');
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
// notifications are updated
|
|
358
|
+
// they are taken back home
|
|
359
|
+
// homepage status shows "Pre-Registration Complete"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "questionnaires",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"auto": "node ../../packages/cli/dist/bin/auto.js",
|
|
7
|
+
"auto:debug": "DEBUG=flow:*,cli:*,auto*,ai*,-*file-syncer,-*flow* node ../../packages/cli/dist/bin/auto.js",
|
|
8
|
+
"start": "dotenv -e .env -- pnpm --parallel start"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@auto-engineer/cli": "workspace:*",
|
|
12
|
+
"@auto-engineer/design-system-importer": "workspace:*",
|
|
13
|
+
"@auto-engineer/flow": "workspace:*",
|
|
14
|
+
"@auto-engineer/frontend-checks": "workspace:*",
|
|
15
|
+
"@auto-engineer/frontend-generator-react-graphql": "workspace:*",
|
|
16
|
+
"@auto-engineer/frontend-implementer": "workspace:*",
|
|
17
|
+
"@auto-engineer/information-architect": "workspace:*",
|
|
18
|
+
"@auto-engineer/message-bus": "workspace:*",
|
|
19
|
+
"@auto-engineer/server-checks": "workspace:*",
|
|
20
|
+
"@auto-engineer/server-generator-apollo-emmett": "workspace:*",
|
|
21
|
+
"@auto-engineer/server-implementer": "workspace:*"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "^24.3.1",
|
|
25
|
+
"chokidar": "^3.6.0",
|
|
26
|
+
"dotenv": "^16.4.5",
|
|
27
|
+
"dotenv-cli": "^9.0.0",
|
|
28
|
+
"tsx": "^3.12.7"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"emitDecoratorMetadata": true,
|
|
8
|
+
"experimentalDecorators": true,
|
|
9
|
+
"outDir": "./dist",
|
|
10
|
+
"noEmit": false,
|
|
11
|
+
"strictNullChecks": true
|
|
12
|
+
},
|
|
13
|
+
"include": ["**/*", "vitest.config.ts"],
|
|
14
|
+
"exclude": ["dist", "node_modules"]
|
|
15
|
+
}
|
package/templates/.gitkeep
DELETED
|
File without changes
|