@freshworks/shiftleft-tools 1.1.8

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.
Files changed (106) hide show
  1. package/README.md +351 -0
  2. package/bin/shiftleft.js +95 -0
  3. package/package.json +57 -0
  4. package/src/commands/doctor.js +208 -0
  5. package/src/commands/init-postman.js +298 -0
  6. package/src/commands/init-rules.js +78 -0
  7. package/src/commands/link.js +172 -0
  8. package/src/commands/protect.js +61 -0
  9. package/src/commands/run-tests.js +182 -0
  10. package/src/commands/setup-pipeline.js +209 -0
  11. package/src/commands/update.js +203 -0
  12. package/src/index.js +4 -0
  13. package/src/utils/copy-tree.js +98 -0
  14. package/src/utils/gitignore.js +26 -0
  15. package/src/utils/logger.js +9 -0
  16. package/src/utils/manifest.js +145 -0
  17. package/src/utils/stack.js +80 -0
  18. package/src/utils/template.js +135 -0
  19. package/templates/AGENTS.md +109 -0
  20. package/templates/CLAUDE.md +3 -0
  21. package/templates/jenkins/Jenkinsfile-java.groovy +432 -0
  22. package/templates/jenkins/Jenkinsfile-node.groovy +450 -0
  23. package/templates/postman/.husky/pre-commit +19 -0
  24. package/templates/postman/.prettierrc.json +5 -0
  25. package/templates/postman/README.md.ejs +147 -0
  26. package/templates/postman/collections/01-core.json.ejs +91 -0
  27. package/templates/postman/config/local.json.ejs +12 -0
  28. package/templates/postman/config/staging.json.ejs +26 -0
  29. package/templates/postman/environments/local.postman_environment.json.ejs +31 -0
  30. package/templates/postman/environments/staging.postman_environment.json.ejs +31 -0
  31. package/templates/postman/gitignore +16 -0
  32. package/templates/postman/npmrc +31 -0
  33. package/templates/postman/package.json.ejs +66 -0
  34. package/templates/postman/run-all-shim.sh +16 -0
  35. package/templates/postman/scripts/auth/generate-jwt.sh +113 -0
  36. package/templates/postman/scripts/auth/get-issuer-secret.sh +140 -0
  37. package/templates/postman/scripts/infra/start-mocks.sh +138 -0
  38. package/templates/postman/scripts/infra/stop-mocks.sh +43 -0
  39. package/templates/postman/scripts/lib/api_coverage.py +1122 -0
  40. package/templates/postman/scripts/lib/cleanup-reports.sh +101 -0
  41. package/templates/postman/scripts/lib/cleanup-stryker.sh +44 -0
  42. package/templates/postman/scripts/lib/report_combined.py +527 -0
  43. package/templates/postman/scripts/lib/report_consolidated.py +363 -0
  44. package/templates/postman/scripts/lib/report_generator.py +121 -0
  45. package/templates/postman/scripts/lib/report_migration.py +156 -0
  46. package/templates/postman/scripts/lib/report_mutation.py +110 -0
  47. package/templates/postman/scripts/lib/report_unit.py +353 -0
  48. package/templates/postman/scripts/lib/report_utils.py +973 -0
  49. package/templates/postman/scripts/report-generators/generate-consolidated-report.sh +445 -0
  50. package/templates/postman/scripts/report-generators/java-api-coverage-matrix.sh +257 -0
  51. package/templates/postman/scripts/report-generators/mutation-report.sh +672 -0
  52. package/templates/postman/scripts/report-generators/node-api-coverage-matrix.sh +167 -0
  53. package/templates/postman/scripts/report-generators/stage-report-artifacts.sh +27 -0
  54. package/templates/postman/scripts/run-all.sh +452 -0
  55. package/templates/postman/scripts/runners/run-mutation-tests.sh +113 -0
  56. package/templates/postman/scripts/runners/run-tests-local.sh +936 -0
  57. package/templates/postman/scripts/runners/run-tests-staging.sh +741 -0
  58. package/templates/postman-node/README.md.ejs +26 -0
  59. package/templates/postman-node/collections/crud/01-bootstrap.json.ejs +34 -0
  60. package/templates/postman-node/config/local.json.ejs +46 -0
  61. package/templates/postman-node/config/staging.json.ejs +31 -0
  62. package/templates/postman-node/local.test.env.ejs +3 -0
  63. package/templates/postman-node/mocks/external.js +14 -0
  64. package/templates/postman-node/package.json.ejs +39 -0
  65. package/templates/postman-node/requirements.txt +1 -0
  66. package/templates/postman-node/scripts/database/cleanup-mysql.sh +12 -0
  67. package/templates/postman-node/scripts/database/run-migrations.js +29 -0
  68. package/templates/postman-node/scripts/database/start-mysql.sh +34 -0
  69. package/templates/postman-node/scripts/database/wait-for-mysql.sh +36 -0
  70. package/templates/postman-node/scripts/lib/api_coverage_node.py +1137 -0
  71. package/templates/postman-node/scripts/lib/fetch-jwt.sh +86 -0
  72. package/templates/postman-node/scripts/lib/run-newman.sh +104 -0
  73. package/templates/postman-node/scripts/lib/setup-database.sh +55 -0
  74. package/templates/postman-node/scripts/lib/start-app.sh +48 -0
  75. package/templates/postman-node/scripts/lib/utils.sh +114 -0
  76. package/templates/postman-node/scripts/report-generators/stage-report-artifacts.sh +26 -0
  77. package/templates/postman-node/scripts/run-all.sh +303 -0
  78. package/templates/postman-node/scripts/runners/run-tests.sh +123 -0
  79. package/templates/postman-node/scripts/setup-mocks.js.ejs +29 -0
  80. package/templates/postman-node/stryker.config.js.ejs +51 -0
  81. package/templates/rules/local-test-setup.mdc +420 -0
  82. package/templates/rules/testing-node.mdc +66 -0
  83. package/templates/rules/testing.mdc +248 -0
  84. package/templates/skills/_shared/postman-standards.md +380 -0
  85. package/templates/skills/enhance-test-pipeline/SKILL-java.md +483 -0
  86. package/templates/skills/enhance-test-pipeline/SKILL-node.md +431 -0
  87. package/templates/skills/enhance-test-pipeline/SKILL.md +9 -0
  88. package/templates/skills/review-test-suite/SKILL-java.md +137 -0
  89. package/templates/skills/review-test-suite/SKILL-node.md +78 -0
  90. package/templates/skills/review-test-suite/SKILL.md +9 -0
  91. package/templates/skills/run-test-suite/SKILL-java.md +186 -0
  92. package/templates/skills/run-test-suite/SKILL-node.md +191 -0
  93. package/templates/skills/run-test-suite/SKILL.md +9 -0
  94. package/templates/skills/setup-api-tests/SKILL-java.md +1094 -0
  95. package/templates/skills/setup-api-tests/SKILL-node.md +141 -0
  96. package/templates/skills/setup-api-tests/SKILL.md +9 -0
  97. package/templates/skills/setup-mutation-tests/SKILL-java.md +303 -0
  98. package/templates/skills/setup-mutation-tests/SKILL-node.md +408 -0
  99. package/templates/skills/setup-mutation-tests/SKILL.md +9 -0
  100. package/templates/skills/setup-test-pipeline/SKILL-java.md +454 -0
  101. package/templates/skills/setup-test-pipeline/SKILL-node.md +318 -0
  102. package/templates/skills/setup-test-pipeline/SKILL.md +9 -0
  103. package/templates/skills/write-api-tests/SKILL-java.md +115 -0
  104. package/templates/skills/write-api-tests/SKILL-node.md +83 -0
  105. package/templates/skills/write-api-tests/SKILL.md +9 -0
  106. package/templates/stryker.config.js +50 -0
@@ -0,0 +1,303 @@
1
+ #!/bin/bash
2
+ #
3
+ # Unified Test & Quality Report Runner (freshapps_api_node)
4
+ #
5
+ # Usage:
6
+ # ./run-all.sh [OPTIONS]
7
+ #
8
+ # Options:
9
+ # --env {local|staging} Target environment for Postman tests (default: local)
10
+ # --skip-unit Skip unit tests (use existing results)
11
+ # --skip-mutation Skip mutation tests (use existing results)
12
+ # --skip-postman Skip Postman API tests (use existing results)
13
+ # --skip-coverage Skip API coverage matrix (use existing results)
14
+ # --skip-report Skip quality report generation
15
+ # --no-delay Skip delays between phases
16
+ # -h, --help Show this help message
17
+
18
+ set -euo pipefail
19
+
20
+ GREEN='\033[0;32m'
21
+ RED='\033[0;31m'
22
+ YELLOW='\033[1;33m'
23
+ BLUE='\033[0;34m'
24
+ CYAN='\033[0;36m'
25
+ BOLD='\033[1m'
26
+ NC='\033[0m'
27
+
28
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
29
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
30
+ POSTMAN_DIR="$(dirname "$SCRIPT_DIR")"
31
+ # shellcheck source=lib/cleanup-stryker.sh
32
+ source "$SCRIPT_DIR/lib/cleanup-stryker.sh"
33
+ REPORTS_DIR="$POSTMAN_DIR/reports"
34
+ TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
35
+
36
+ POSTMAN_ENV="${POSTMAN_ENV:-local}"
37
+ SKIP_UNIT=false
38
+ SKIP_MUTATION=false
39
+ SKIP_POSTMAN=false
40
+ SKIP_COVERAGE=false
41
+ SKIP_REPORT=false
42
+ SKIP_DELAY=false
43
+
44
+ UNIT_OK=false
45
+ MUTATION_OK=false
46
+ POSTMAN_OK=false
47
+ COVERAGE_OK=false
48
+ POSTMAN_RESULT=0
49
+
50
+ while [[ $# -gt 0 ]]; do
51
+ case $1 in
52
+ -h|--help) head -18 "$0" | tail -14; exit 0 ;;
53
+ --env) POSTMAN_ENV="$2"; shift 2 ;;
54
+ --skip-unit) SKIP_UNIT=true; shift ;;
55
+ --skip-mutation) SKIP_MUTATION=true; shift ;;
56
+ --skip-postman) SKIP_POSTMAN=true; shift ;;
57
+ --skip-coverage) SKIP_COVERAGE=true; shift ;;
58
+ --skip-report) SKIP_REPORT=true; shift ;;
59
+ --no-delay) SKIP_DELAY=true; shift ;;
60
+ *) echo -e "${RED}Unknown option: $1${NC}"; exit 1 ;;
61
+ esac
62
+ done
63
+
64
+ if [[ ! "$POSTMAN_ENV" =~ ^(local|staging)$ ]]; then
65
+ echo -e "${RED}Invalid environment: $POSTMAN_ENV${NC}"
66
+ exit 1
67
+ fi
68
+
69
+ cleanup() {
70
+ local pid_file="$POSTMAN_DIR/.app.pid"
71
+ if [ -f "$pid_file" ]; then
72
+ APP_PID=$(cat "$pid_file" 2>/dev/null || echo "")
73
+ if [ -n "$APP_PID" ] && ps -p "$APP_PID" > /dev/null 2>&1; then
74
+ echo -e "${YELLOW}Stopping application (PID $APP_PID)...${NC}"
75
+ kill "$APP_PID" 2>/dev/null || true
76
+ sleep 2
77
+ ps -p "$APP_PID" > /dev/null 2>&1 && kill -9 "$APP_PID" 2>/dev/null || true
78
+ fi
79
+ rm -f "$pid_file"
80
+ fi
81
+ cleanup_stryker "$PROJECT_ROOT"
82
+ }
83
+
84
+ trap cleanup EXIT
85
+
86
+ mkdir -p "$REPORTS_DIR"
87
+
88
+ echo -e "${YELLOW}Cleaning up old reports...${NC}"
89
+ _keep_latest() {
90
+ local pattern="$1" keep="${2:-3}"
91
+ # shellcheck disable=SC2012
92
+ ls -t $pattern 2>/dev/null | tail -n +$((keep + 1)) | xargs rm -f 2>/dev/null || true
93
+ }
94
+ _keep_latest "$REPORTS_DIR/quality-report-*.html" 3
95
+ if [ "$SKIP_POSTMAN" = false ]; then
96
+ # Remove only THIS environment's stale per-collection Newman HTML reports
97
+ # (they are about to be regenerated). Scoping the delete to the current env
98
+ # leaves the other env's reports — and the "View Details" links of its kept
99
+ # consolidated report — intact.
100
+ find "$REPORTS_DIR" -maxdepth 1 -name "test-${POSTMAN_ENV}-*.html" \
101
+ -delete 2>/dev/null || true
102
+ fi
103
+ if [ "$SKIP_POSTMAN" = false ]; then
104
+ _keep_latest "$REPORTS_DIR/consolidated-*.html" 3
105
+ _keep_latest "$REPORTS_DIR/consolidated-*.json" 3
106
+ rm -rf "$REPORTS_DIR"/json 2>/dev/null || true
107
+ fi
108
+ if [ "$SKIP_COVERAGE" = false ]; then
109
+ _keep_latest "$REPORTS_DIR/api-coverage-matrix-*.html" 3
110
+ _keep_latest "$REPORTS_DIR/api-coverage-matrix-*.json" 3
111
+ fi
112
+ echo -e "${GREEN}Old reports cleaned${NC}"
113
+
114
+ echo -e "${YELLOW}Cleaning up stale Stryker processes and temp files...${NC}"
115
+ cleanup_stryker "$PROJECT_ROOT"
116
+ echo -e "${GREEN}Stryker cleanup done${NC}"
117
+ echo ""
118
+
119
+ [ -t 1 ] && clear || true
120
+ echo -e "${BOLD}${BLUE}UNIFIED TEST & QUALITY REPORT RUNNER${NC}"
121
+ echo ""
122
+ if [ "$SKIP_DELAY" = "false" ]; then
123
+ echo -e "${YELLOW}Starting in 2 seconds... (Ctrl+C to cancel)${NC}"
124
+ sleep 2
125
+ fi
126
+
127
+ MOCHA_XML="$PROJECT_ROOT/coverage/unit-tests/test-results.xml"
128
+ LCOV="$PROJECT_ROOT/coverage/unit-tests/lcov.info"
129
+ STRYKER_JSON="$PROJECT_ROOT/coverage/mutation/mutation-report.json"
130
+
131
+ # Phase 1: Unit tests
132
+ echo ""
133
+ echo -e "${CYAN}Phase 1: Unit Tests + nyc Coverage${NC}"
134
+ if [ "$SKIP_UNIT" = false ]; then
135
+ cd "$PROJECT_ROOT"
136
+ if yarn --ignore-engines unit-tests; then
137
+ echo -e "${GREEN}Unit tests completed${NC}"
138
+ else
139
+ echo -e "${RED}Unit tests had failures (continuing)${NC}"
140
+ fi
141
+ UNIT_OK=true
142
+ else
143
+ echo -e "${YELLOW}Skipping unit tests${NC}"
144
+ [ -f "$MOCHA_XML" ] || [ -f "$LCOV" ] && UNIT_OK=true
145
+ fi
146
+
147
+ # Phase 2: Mutation — fast mode (changed files vs origin/master); Jenkins uses mutation-tests:full
148
+ echo ""
149
+ echo -e "${CYAN}Phase 2: Stryker Mutation Testing (changed files vs origin/master)${NC}"
150
+ if [ "$SKIP_MUTATION" = false ]; then
151
+ if [ "$SKIP_UNIT" = true ] && [ ! -d "$PROJECT_ROOT/.nyc_output" ]; then
152
+ echo -e "${YELLOW}Warning: .nyc_output missing; perTest coverage may fail. Run unit tests first.${NC}"
153
+ fi
154
+ cd "$PROJECT_ROOT"
155
+ if yarn --ignore-engines mutation-tests; then
156
+ MUTATION_OK=true
157
+ echo -e "${GREEN}Mutation tests completed${NC}"
158
+ else
159
+ echo -e "${RED}Mutation tests failed (continuing)${NC}"
160
+ fi
161
+ else
162
+ echo -e "${YELLOW}Skipping mutation tests${NC}"
163
+ [ -f "$STRYKER_JSON" ] && MUTATION_OK=true
164
+ fi
165
+
166
+ # Phase 3: Postman
167
+ echo ""
168
+ echo -e "${CYAN}Phase 3: Postman API Tests ($POSTMAN_ENV)${NC}"
169
+ POSTMAN_PASSED=0
170
+ POSTMAN_FAILED=0
171
+ CONSOLIDATED_JSON=""
172
+
173
+ if [ "$SKIP_POSTMAN" = false ]; then
174
+ set +e
175
+ "$SCRIPT_DIR/runners/run-tests.sh" "$POSTMAN_ENV"
176
+ POSTMAN_RESULT=$?
177
+ set -e
178
+ CONSOLIDATED_JSON=$(ls -t "$REPORTS_DIR"/consolidated-*.json 2>/dev/null | head -1 || true)
179
+ if [ -n "$CONSOLIDATED_JSON" ] && [ -f "$CONSOLIDATED_JSON" ]; then
180
+ POSTMAN_PASSED=$(jq '.summary.collections.passed // 0' "$CONSOLIDATED_JSON" 2>/dev/null || echo "0")
181
+ POSTMAN_FAILED=$(jq '.summary.collections.failed // 0' "$CONSOLIDATED_JSON" 2>/dev/null || echo "0")
182
+ POSTMAN_OK=true
183
+ fi
184
+ else
185
+ echo -e "${YELLOW}Skipping Postman tests${NC}"
186
+ CONSOLIDATED_JSON=$(ls -t "$REPORTS_DIR"/consolidated-*.json 2>/dev/null | head -1 || true)
187
+ [ -n "$CONSOLIDATED_JSON" ] && POSTMAN_OK=true
188
+ fi
189
+
190
+ # Phase 4: API coverage
191
+ echo ""
192
+ echo -e "${CYAN}Phase 4: API Coverage Matrix${NC}"
193
+ API_COVERAGE_JSON=""
194
+ if [ "$SKIP_COVERAGE" = false ]; then
195
+ if "$SCRIPT_DIR/report-generators/node-api-coverage-matrix.sh" "$PROJECT_ROOT/src/controllers" "$POSTMAN_DIR"; then
196
+ COVERAGE_OK=true
197
+ echo -e "${GREEN}API coverage matrix generated${NC}"
198
+ else
199
+ echo -e "${RED}API coverage matrix failed${NC}"
200
+ fi
201
+ else
202
+ echo -e "${YELLOW}Skipping API coverage matrix${NC}"
203
+ ls "$REPORTS_DIR"/api-coverage-matrix-*.json 1>/dev/null 2>&1 && COVERAGE_OK=true
204
+ fi
205
+
206
+ COVERAGE_JSON_FILE=$(ls -t "$REPORTS_DIR"/api-coverage-matrix-*.json 2>/dev/null | head -1 || true)
207
+ if [ -n "$COVERAGE_JSON_FILE" ] && [ -f "$COVERAGE_JSON_FILE" ]; then
208
+ API_COVERAGE_JSON=$(cat "$COVERAGE_JSON_FILE")
209
+ fi
210
+
211
+ # Phase 5: Combined report
212
+ echo ""
213
+ echo -e "${CYAN}Phase 5: Combined Quality Report${NC}"
214
+
215
+ # Install Python dependencies if needed (defusedxml for XXE protection)
216
+ if [ "$SKIP_REPORT" = false ] || [ "$SKIP_COVERAGE" = false ]; then
217
+ echo -e "${YELLOW}Installing Python dependencies...${NC}"
218
+ if [ -f "$PROJECT_ROOT/requirements.txt" ]; then
219
+ python3 -m pip install --upgrade pip >/dev/null 2>&1
220
+ python3 -m pip install -r "$PROJECT_ROOT/requirements.txt" >/dev/null 2>&1 || {
221
+ echo -e "${RED}Failed to install Python dependencies${NC}"
222
+ exit 1
223
+ }
224
+ echo -e "${GREEN}Python dependencies installed${NC}"
225
+ fi
226
+ fi
227
+
228
+ if [ "$SKIP_REPORT" = false ]; then
229
+ POSTMAN_TOTAL_ASSERTIONS=0
230
+ POSTMAN_PASSED_ASSERTIONS=0
231
+ POSTMAN_FAILED_ASSERTIONS=0
232
+ POSTMAN_TOTAL_REQUESTS=0
233
+ POSTMAN_DURATION="0"
234
+
235
+ CONSOLIDATED_JSON="${CONSOLIDATED_JSON:-$(ls -t "$REPORTS_DIR"/consolidated-*.json 2>/dev/null | head -1 || true)}"
236
+ if [ -n "$CONSOLIDATED_JSON" ] && [ -f "$CONSOLIDATED_JSON" ]; then
237
+ POSTMAN_TOTAL_ASSERTIONS=$(jq '.summary.assertions.total // 0' "$CONSOLIDATED_JSON" 2>/dev/null || echo "0")
238
+ POSTMAN_FAILED_ASSERTIONS=$(jq '.summary.assertions.failed // 0' "$CONSOLIDATED_JSON" 2>/dev/null || echo "0")
239
+ POSTMAN_TOTAL_REQUESTS=$(jq '.summary.requests.total // 0' "$CONSOLIDATED_JSON" 2>/dev/null || echo "0")
240
+ POSTMAN_TOTAL_DURATION=$(jq '.summary.duration_ms // 0' "$CONSOLIDATED_JSON" 2>/dev/null || echo "0")
241
+ POSTMAN_PASSED_ASSERTIONS=$((POSTMAN_TOTAL_ASSERTIONS - POSTMAN_FAILED_ASSERTIONS))
242
+ POSTMAN_DURATION=$(echo "scale=2; $POSTMAN_TOTAL_DURATION / 1000" | bc 2>/dev/null || echo "0")
243
+ fi
244
+
245
+ COMBINED_OUTPUT="$REPORTS_DIR/quality-report-$TIMESTAMP.html"
246
+
247
+ "$SCRIPT_DIR/report-generators/stage-report-artifacts.sh" "$PROJECT_ROOT" "$REPORTS_DIR"
248
+
249
+ REPORT_ARGS=(combined "$COMBINED_OUTPUT" --logo "API Service")
250
+
251
+ [ -f "$MOCHA_XML" ] && REPORT_ARGS+=(--mocha-xml "$MOCHA_XML")
252
+ [ -f "$LCOV" ] && REPORT_ARGS+=(--lcov "$LCOV")
253
+ [ -f "$STRYKER_JSON" ] && REPORT_ARGS+=(--stryker-json "$STRYKER_JSON")
254
+
255
+ REPORT_ARGS+=(--postman-assertions-total "$POSTMAN_TOTAL_ASSERTIONS")
256
+ REPORT_ARGS+=(--postman-assertions-passed "$POSTMAN_PASSED_ASSERTIONS")
257
+ REPORT_ARGS+=(--postman-assertions-failed "$POSTMAN_FAILED_ASSERTIONS")
258
+ REPORT_ARGS+=(--postman-requests "$POSTMAN_TOTAL_REQUESTS")
259
+ REPORT_ARGS+=(--postman-duration "$POSTMAN_DURATION")
260
+ REPORT_ARGS+=(--postman-collections-passed "$POSTMAN_PASSED")
261
+ REPORT_ARGS+=(--postman-collections-failed "$POSTMAN_FAILED")
262
+
263
+ TEMP_COVERAGE=""
264
+ if [ -n "$API_COVERAGE_JSON" ]; then
265
+ TEMP_COVERAGE="/tmp/api-coverage-data-$$.json"
266
+ # Ensure temp file is cleaned up on exit
267
+ trap 'rm -f "$TEMP_COVERAGE" 2>/dev/null || true' EXIT
268
+ echo "$API_COVERAGE_JSON" > "$TEMP_COVERAGE"
269
+ REPORT_ARGS+=(--api-coverage-file "$TEMP_COVERAGE")
270
+ fi
271
+
272
+ API_COVERAGE_HTML=$(ls -t "$REPORTS_DIR"/api-coverage-matrix-*.html 2>/dev/null | head -1 || true)
273
+ [ -n "$API_COVERAGE_HTML" ] && REPORT_ARGS+=(--api-coverage-html "$API_COVERAGE_HTML")
274
+
275
+ # Always (re)generate the consolidated HTML for THIS run's timestamp so the
276
+ # combined report never links to a stale consolidated whose per-collection
277
+ # detail files have been cleaned up. Fall back to the newest only if this run
278
+ # produced no consolidated JSON to render.
279
+ POSTMAN_CONSOLIDATED_HTML="$REPORTS_DIR/consolidated-${POSTMAN_ENV}-${TIMESTAMP}.html"
280
+ CONSOLIDATED_JSON_THIS_RUN="$REPORTS_DIR/consolidated-${POSTMAN_ENV}-${TIMESTAMP}.json"
281
+ if [ ! -f "$POSTMAN_CONSOLIDATED_HTML" ] && [ -f "$CONSOLIDATED_JSON_THIS_RUN" ]; then
282
+ "$SCRIPT_DIR/report-generators/generate-consolidated-report.sh" "$POSTMAN_ENV" "$TIMESTAMP" "$REPORTS_DIR" "$POSTMAN_PASSED" "$POSTMAN_FAILED" 0 >/dev/null 2>&1 || true
283
+ fi
284
+ if [ ! -f "$POSTMAN_CONSOLIDATED_HTML" ]; then
285
+ POSTMAN_CONSOLIDATED_HTML=$(ls -t "$REPORTS_DIR"/consolidated-*.html 2>/dev/null | head -1 || true)
286
+ fi
287
+ [ -n "$POSTMAN_CONSOLIDATED_HTML" ] && [ -f "$POSTMAN_CONSOLIDATED_HTML" ] && REPORT_ARGS+=(--postman-consolidated-html "$POSTMAN_CONSOLIDATED_HTML")
288
+
289
+ python3 "$SCRIPT_DIR/lib/report_generator.py" "${REPORT_ARGS[@]}"
290
+ [ -n "$TEMP_COVERAGE" ] && rm -f "$TEMP_COVERAGE"
291
+
292
+ if [ -f "$COMBINED_OUTPUT" ]; then
293
+ echo -e "${GREEN}Combined report: $COMBINED_OUTPUT${NC}"
294
+ [[ "$OSTYPE" == darwin* ]] && open "$COMBINED_OUTPUT" 2>/dev/null || true
295
+ else
296
+ echo -e "${RED}Failed to generate combined report${NC}"
297
+ exit 1
298
+ fi
299
+ else
300
+ echo -e "${YELLOW}Skipping report generation${NC}"
301
+ fi
302
+
303
+ exit $POSTMAN_RESULT
@@ -0,0 +1,123 @@
1
+ #!/bin/bash
2
+ # =============================================================================
3
+ # Unified Test Runner - Config-Driven
4
+ # =============================================================================
5
+ # Runs integration tests for any environment (local, dev, staging)
6
+ # Configuration determines what gets set up and how authentication works
7
+ #
8
+ # Usage:
9
+ # ./run-tests.sh [environment]
10
+ #
11
+ # Examples:
12
+ # ./run-tests.sh local # Local with Podman MySQL
13
+ # ./run-tests.sh dev # Dev with AWS auth
14
+ # ./run-tests.sh staging # Staging with AWS auth
15
+ #
16
+ # Environment Variables (optional overrides):
17
+ # AWS_PROFILE=profile # Override AWS profile from config
18
+ # =============================================================================
19
+
20
+ set -euo pipefail
21
+
22
+ RUNNERS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
23
+ SCRIPT_DIR="$(cd "$RUNNERS_DIR/.." && pwd)"
24
+ POSTMAN_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
25
+ PROJECT_ROOT="$(cd "$POSTMAN_DIR/.." && pwd)"
26
+
27
+ # Source utilities
28
+ source "$SCRIPT_DIR/lib/utils.sh"
29
+
30
+ # Parse arguments
31
+ ENVIRONMENT="${1:-local}"
32
+ CONFIG_FILE="$POSTMAN_DIR/config/${ENVIRONMENT}.json"
33
+
34
+ # Validate environment
35
+ if [ ! -f "$CONFIG_FILE" ]; then
36
+ error "Configuration not found: $CONFIG_FILE"
37
+ echo ""
38
+ echo "Available environments:"
39
+ ls -1 "$POSTMAN_DIR/config"/*.json 2>/dev/null | xargs -n1 basename | sed 's/.json$//' | sed 's/^/ - /' || echo " (none found)"
40
+ exit 1
41
+ fi
42
+
43
+ log_header "Freshapps API Integration Tests"
44
+ log_info "Environment: ${ENVIRONMENT}"
45
+ log_info "Config: $(basename $CONFIG_FILE)"
46
+ echo ""
47
+
48
+ # Load configuration
49
+ API_URL=$(jq -r '.api_url' "$CONFIG_FILE")
50
+ AUTH_TYPE=$(jq -r '.auth.type' "$CONFIG_FILE")
51
+
52
+ # Setup flags (with env var overrides)
53
+ SETUP_DB=$(jq -r '.setup.database.enabled' "$CONFIG_FILE")
54
+ if [ "${SKIP_DB:-}" = "true" ]; then
55
+ SETUP_DB="false"
56
+ fi
57
+
58
+ SETUP_APP=$(jq -r '.setup.app.enabled' "$CONFIG_FILE")
59
+ if [ "${SKIP_APP:-}" = "true" ]; then
60
+ SETUP_APP="false"
61
+ fi
62
+
63
+ SETUP_MIGRATIONS=$(jq -r '.setup.migrations.enabled' "$CONFIG_FILE")
64
+
65
+ CLEANUP_ENABLED="true"
66
+ if [ "${SKIP_CLEANUP:-}" = "true" ]; then
67
+ CLEANUP_ENABLED="false"
68
+ fi
69
+
70
+ log_info "API URL: ${API_URL}"
71
+ log_info "Auth Type: ${AUTH_TYPE}"
72
+ log_info "Setup Database: ${SETUP_DB}"
73
+ log_info "Setup App: ${SETUP_APP}"
74
+ echo ""
75
+
76
+ # Trap cleanup
77
+ trap cleanup EXIT
78
+
79
+ # Step 1: Database Setup
80
+ if [ "$SETUP_DB" = "true" ]; then
81
+ log_step "1" "Setting up database"
82
+ source "$SCRIPT_DIR/lib/setup-database.sh"
83
+ setup_database "$CONFIG_FILE"
84
+ echo ""
85
+ fi
86
+
87
+ # Step 2: Run Migrations
88
+ if [ "$SETUP_MIGRATIONS" = "true" ]; then
89
+ log_step "2" "Running migrations"
90
+ source "$SCRIPT_DIR/lib/setup-database.sh"
91
+ run_migrations "$CONFIG_FILE"
92
+ echo ""
93
+ fi
94
+
95
+ # Step 3: Start Application
96
+ if [ "$SETUP_APP" = "true" ]; then
97
+ log_step "3" "Starting application"
98
+ source "$SCRIPT_DIR/lib/start-app.sh"
99
+ start_application "$CONFIG_FILE"
100
+ echo ""
101
+ fi
102
+
103
+ # Step 4: Generate JWT Token
104
+ log_step "4" "Generating authentication token"
105
+ source "$SCRIPT_DIR/lib/fetch-jwt.sh"
106
+ JWT_TOKEN=$(fetch_jwt "$CONFIG_FILE")
107
+ log_success "Token generated"
108
+ echo ""
109
+
110
+ # Step 5: Update Environment File
111
+ log_step "5" "Updating Postman environment"
112
+ update_postman_environment "$ENVIRONMENT" "$JWT_TOKEN" "$API_URL" "$CONFIG_FILE"
113
+ echo ""
114
+
115
+ # Step 6: Run Tests
116
+ log_step "6" "Running Newman tests"
117
+ source "$SCRIPT_DIR/lib/run-newman.sh"
118
+ run_newman_tests "$ENVIRONMENT"
119
+ echo ""
120
+
121
+ # Cleanup handled by trap
122
+ echo ""
123
+ log_header "Tests Completed Successfully!"
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * nock mock orchestrator for <%= serviceName %> integration tests.
5
+ * Load from your app entry when NODE_ENV=integration-tests:
6
+ *
7
+ * if (process.env.NODE_ENV === 'integration-tests') {
8
+ * require('../postman/scripts/setup-mocks').setupMocks();
9
+ * }
10
+ */
11
+ const nock = require('nock');
12
+ const { setupExternalMocks } = require('../mocks/external');
13
+
14
+ function setupMocks() {
15
+ nock.disableNetConnect();
16
+ nock.enableNetConnect(/(localhost|127\.0\.0\.1)/);
17
+
18
+ setupExternalMocks(nock);
19
+
20
+ // Add service-specific mocks in postman/mocks/ and require them here.
21
+ console.log('[setup-mocks] External HTTP mocks enabled');
22
+ }
23
+
24
+ function teardownMocks() {
25
+ nock.cleanAll();
26
+ nock.enableNetConnect();
27
+ }
28
+
29
+ module.exports = { setupMocks, teardownMocks };
@@ -0,0 +1,51 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Stryker mutation testing for <%= serviceName %>.
5
+ * Customize mutate paths after inspecting your src/ layout.
6
+ * Exclude external-service wrappers (HTTP clients, AWS SDK, etc.).
7
+ */
8
+ module.exports = {
9
+ packageManager: 'yarn',
10
+ testRunner: 'mocha',
11
+ reporters: ['html', 'json', 'clear-text', 'progress'],
12
+ htmlReporter: {
13
+ fileName: 'coverage/mutation/index.html',
14
+ },
15
+ jsonReporter: {
16
+ fileName: 'coverage/mutation/mutation-report.json',
17
+ },
18
+ // IMPORTANT: List only business-logic folders — never `src/**/*.js` (Stryker will run for hours).
19
+ // Run `/setup-mutation-tests` to audit src/ and set paths file-by-file.
20
+ mutate: [
21
+ 'src/actions/**/*.js',
22
+ 'src/services/**/*.js',
23
+ 'src/serializers/**/*.js',
24
+ 'src/middlewares/**/*.js',
25
+ '!src/**/index.js',
26
+ '!src/**/app.js',
27
+ '!src/controllers/**',
28
+ '!src/routes/**',
29
+ '!src/config/**',
30
+ '!src/constants/**',
31
+ '!src/migrations/**',
32
+ '!src/seeders/**',
33
+ '!src/models/**',
34
+ ],
35
+ coverageAnalysis: 'perTest',
36
+ concurrency: 4,
37
+ incremental: true,
38
+ incrementalFile: 'coverage/mutation/stryker-incremental.json',
39
+ ignorePatterns: ['postman/**', 'coverage/**', 'node_modules/**'],
40
+ mochaOpts: {
41
+ files: 'test/unit/**/*.test.js',
42
+ require: ['test/unit/setup.js'],
43
+ timeout: 10000,
44
+ },
45
+ thresholds: {
46
+ high: 80,
47
+ low: 60,
48
+ break: 0,
49
+ },
50
+ tempDirName: 'coverage/mutation/.stryker-tmp',
51
+ };