@specwright/plugin 0.1.2 → 0.1.4

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.
@@ -11,9 +11,12 @@
11
11
  */
12
12
 
13
13
  import { expect } from '@playwright/test';
14
- import _ from 'lodash';
15
14
  import { generateValueForField } from './testDataGenerator.js';
16
15
 
16
+ // Simple replacements for lodash — avoids a dependency for 2 functions
17
+ const snakeCase = (str) => str.replace(/([a-z])([A-Z])/g, '$1_$2').replace(/[\s\-]+/g, '_').toLowerCase();
18
+ const kebabCase = (str) => str.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/[\s_]+/g, '-').toLowerCase();
19
+
17
20
  // ─────────────────────────────────────────────────────────────
18
21
  // FIELD_TYPES — declarative type constants
19
22
  // ─────────────────────────────────────────────────────────────
@@ -76,7 +79,7 @@ export async function processDataTable(page, dataTable, config = {}) {
76
79
  }
77
80
  // Cache SharedGenerated values for later <from_test_data> reads
78
81
  if (valueType === 'sharedgenerated') {
79
- const cacheKey = mapping[fieldName] || _.snakeCase(fieldName);
82
+ const cacheKey = mapping[fieldName] || snakeCase(fieldName);
80
83
  if (!page.testData) page.testData = {};
81
84
  page.testData[cacheKey] = value;
82
85
  // Also write to featureDataCache for cross-scenario persistence
@@ -90,7 +93,7 @@ export async function processDataTable(page, dataTable, config = {}) {
90
93
  }
91
94
  } else if (value === '<from_test_data>') {
92
95
  // Read: look up from page.testData or featureDataCache
93
- const cacheKey = mapping[fieldName] || _.snakeCase(fieldName);
96
+ const cacheKey = mapping[fieldName] || snakeCase(fieldName);
94
97
  if (page.testData?.[cacheKey] !== undefined) {
95
98
  value = page.testData[cacheKey];
96
99
  console.log(`📖 Read "${fieldName}" → ${cacheKey}: ${value}`);
@@ -146,7 +149,7 @@ export async function validateExpectations(page, dataTable, config = {}) {
146
149
 
147
150
  // ── Resolve <from_test_data> placeholder ──
148
151
  if (expectedValue === '<from_test_data>') {
149
- const cacheKey = mapping[fieldName] || _.snakeCase(fieldName);
152
+ const cacheKey = mapping[fieldName] || snakeCase(fieldName);
150
153
  if (page.testData?.[cacheKey] !== undefined) {
151
154
  expectedValue = page.testData[cacheKey];
152
155
  console.log(`✅ Validate "${fieldName}" → ${cacheKey}: ${expectedValue}`);
@@ -184,7 +187,7 @@ export async function validateExpectations(page, dataTable, config = {}) {
184
187
  * Tries: testID → name → placeholder → label → CSS fallback
185
188
  */
186
189
  export async function fillFieldByName(container, fieldName, value) {
187
- const fieldKebab = _.kebabCase(fieldName);
190
+ const fieldKebab = kebabCase(fieldName);
188
191
 
189
192
  const strategies = [
190
193
  () => container.getByTestId(fieldKebab),
@@ -221,7 +224,7 @@ export async function fillFieldByName(container, fieldName, value) {
221
224
  * Opens the dropdown, finds the option by text, clicks it.
222
225
  */
223
226
  export async function selectDropDownByTestId(page, fieldName, value, autoKebab = true) {
224
- const testId = autoKebab ? _.kebabCase(fieldName) : fieldName;
227
+ const testId = autoKebab ? kebabCase(fieldName) : fieldName;
225
228
 
226
229
  const dropdownContainer = page.getByTestId(testId);
227
230
  await dropdownContainer.waitFor({ state: 'visible', timeout: 5000 });
package/install.sh CHANGED
@@ -112,6 +112,61 @@ echo "📦 Step 5: Installing documentation..."
112
112
  cp "$PLUGIN_DIR/README-TESTING.md" "$TARGET_DIR/"
113
113
  echo " ✅ README-TESTING.md installed"
114
114
 
115
+ # ── Step 6: Merge dependencies + scripts into package.json ──
116
+ echo "📦 Step 6: Merging dependencies and scripts into package.json..."
117
+ if [ -f "$TARGET_DIR/package.json" ]; then
118
+ node -e "
119
+ const fs = require('fs');
120
+ const path = require('path');
121
+
122
+ const targetPkgPath = path.join('$TARGET_DIR', 'package.json');
123
+ const snippetPath = path.join('$PLUGIN_DIR', 'package.json.snippet');
124
+
125
+ const pkg = JSON.parse(fs.readFileSync(targetPkgPath, 'utf-8'));
126
+ const snippet = JSON.parse(fs.readFileSync(snippetPath, 'utf-8'));
127
+
128
+ // Merge devDependencies
129
+ if (snippet.devDependencies) {
130
+ pkg.devDependencies = { ...(pkg.devDependencies || {}), ...snippet.devDependencies };
131
+ }
132
+
133
+ // Merge scripts (don't overwrite existing)
134
+ if (snippet.scripts) {
135
+ pkg.scripts = pkg.scripts || {};
136
+ for (const [key, val] of Object.entries(snippet.scripts)) {
137
+ if (!pkg.scripts[key]) {
138
+ pkg.scripts[key] = val;
139
+ }
140
+ }
141
+ }
142
+
143
+ fs.writeFileSync(targetPkgPath, JSON.stringify(pkg, null, 2) + '\n');
144
+ console.log(' ✅ package.json updated (devDependencies + scripts merged)');
145
+ "
146
+ else
147
+ echo " ⚠️ No package.json found in target — skipping dependency merge"
148
+ echo " Manually merge contents of package.json.snippet into your package.json"
149
+ fi
150
+
151
+ # ── Step 7: Append .gitignore entries ──
152
+ echo "📦 Step 7: Updating .gitignore..."
153
+ if [ -f "$TARGET_DIR/.gitignore" ]; then
154
+ # Only append lines that don't already exist
155
+ while IFS= read -r line; do
156
+ [ -z "$line" ] && continue
157
+ [[ "$line" == \#* ]] && continue
158
+ grep -qF "$line" "$TARGET_DIR/.gitignore" 2>/dev/null || echo "$line" >> "$TARGET_DIR/.gitignore"
159
+ done < "$PLUGIN_DIR/.gitignore.snippet"
160
+ echo " ✅ .gitignore updated"
161
+ else
162
+ cp "$PLUGIN_DIR/.gitignore.snippet" "$TARGET_DIR/.gitignore"
163
+ echo " ✅ .gitignore created"
164
+ fi
165
+
166
+ # ── Step 8: Create migrations/files directory ──
167
+ mkdir -p "$TARGET_DIR/e2e-tests/data/migrations/files"
168
+ touch "$TARGET_DIR/e2e-tests/data/migrations/files/.gitkeep"
169
+
115
170
  # ── Done ──
116
171
  echo ""
117
172
  echo "╔══════════════════════════════════════════════╗"
@@ -120,29 +175,24 @@ echo "╚═══════════════════════
120
175
  echo ""
121
176
  echo "📋 Next steps:"
122
177
  echo ""
123
- echo " 1. Merge devDependencies + scripts from e2e-plugin/package.json.snippet"
124
- echo " into your package.json, then run: pnpm install"
125
- echo ""
126
- echo " 2. Install Playwright browsers: pnpx playwright install"
178
+ echo " 1. Install dependencies: pnpm install"
127
179
  echo ""
128
- echo " 3. Append lines from e2e-plugin/.gitignore.snippet"
129
- echo " to your .gitignore"
180
+ echo " 2. Install Playwright browsers: npx playwright install"
130
181
  echo ""
131
- echo " 4. Update e2e-tests/data/authenticationData.js"
182
+ echo " 3. Update e2e-tests/data/authenticationData.js"
132
183
  echo " → Set your app's login form testIDs"
133
184
  echo ""
134
- echo " 5. Update e2e-tests/data/testConfig.js"
185
+ echo " 4. Update e2e-tests/data/testConfig.js"
135
186
  echo " → Set your app's routes"
136
187
  echo ""
137
- echo " 6. Set credentials in .env:"
188
+ echo " 5. Set credentials in .env:"
138
189
  echo " TEST_USER_EMAIL=your-email@example.com"
139
190
  echo " TEST_USER_PASSWORD=your-password"
140
191
  echo " BASE_URL=http://localhost:5173"
141
192
  echo ""
142
- echo " 7. Start dev server and run tests:"
193
+ echo " 6. Start dev server and run tests:"
143
194
  echo " pnpm test:bdd:auth # Run authentication tests"
144
195
  echo " pnpm test:bdd # Run all tests (except auth)"
145
- echo " pnpm test:bdd:all # Run everything including auth"
146
196
  echo ""
147
- echo " 8. Generate more tests: /e2e-automate (Claude Code CLI)"
197
+ echo " 7. Generate more tests: /e2e-automate (Claude Code CLI)"
148
198
  echo ""
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@specwright/plugin",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Drop-in E2E test automation framework plugin — Playwright BDD + Claude Code agents",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -21,7 +21,6 @@
21
21
  "@faker-js/faker": "^10.3.0",
22
22
  "@playwright/test": "^1.54.1",
23
23
  "dotenv": "^17.2.0",
24
- "lodash": "^4.17.23",
25
24
  "playwright-bdd": "^8.5.0"
26
25
  }
27
26
  }