e2e-testid 1.0.3

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 (3) hide show
  1. package/README.md +166 -0
  2. package/index.js +126 -0
  3. package/package.json +45 -0
package/README.md ADDED
@@ -0,0 +1,166 @@
1
+ Here is a clean, professional `README.md` you can use for your package:
2
+
3
+ ---
4
+
5
+ # e2e-testid
6
+
7
+ A lightweight utility for generating stable and consistent `data-testid` values for E2E testing.
8
+
9
+ It helps teams standardize selectors, avoid flaky tests, and create namespaced test IDs in a clean and scalable way.
10
+
11
+ ---
12
+
13
+ ## ✨ Why e2e-testid?
14
+
15
+ E2E tests often break because:
16
+
17
+ * Selectors are inconsistent
18
+ * Developers rename classes
19
+ * IDs are not standardized
20
+ * There is no naming convention
21
+
22
+ `e2e-testid` solves this by providing:
23
+
24
+ * Consistent `data-testid` naming
25
+ * Namespacing support (`Auth.Login.Submit`)
26
+ * Automatic test id builder per feature
27
+ * Optional runtime toggle (enable only in E2E builds)
28
+
29
+ ---
30
+
31
+ ## 📦 Installation
32
+
33
+ ```bash
34
+ npm install e2e-testid
35
+ ```
36
+
37
+ or
38
+
39
+ ```bash
40
+ yarn add e2e-testid
41
+ ```
42
+
43
+ ---
44
+
45
+ ## 🚀 Basic Usage
46
+
47
+ ```js
48
+ const { tid } = require("e2e-testid");
49
+
50
+ <button {...tid("Auth.Login.Submit")}>
51
+ Login
52
+ </button>
53
+ ```
54
+
55
+ Output:
56
+
57
+ ```html
58
+ <button data-testid="Auth.Login.Submit">
59
+ Login
60
+ </button>
61
+ ```
62
+
63
+ ---
64
+
65
+ ## 🏗 Namespaced Builder
66
+
67
+ Create a namespace for a feature:
68
+
69
+ ```js
70
+ const { createTid } = require("e2e-testid");
71
+
72
+ const t = createTid("Auth.Login");
73
+
74
+ <button {...t.tid("Submit")}>
75
+ Login
76
+ </button>
77
+ ```
78
+
79
+ Result:
80
+
81
+ ```html
82
+ <button data-testid="Auth.Login.Submit">
83
+ ```
84
+
85
+ ---
86
+
87
+ ## 🔁 Child Namespaces
88
+
89
+ ```js
90
+ const auth = createTid("Auth");
91
+ const login = auth.child("Login");
92
+
93
+ login.tid("Submit");
94
+ ```
95
+
96
+ Generates:
97
+
98
+ ```
99
+ Auth.Login.Submit
100
+ ```
101
+
102
+ ---
103
+
104
+ ## ⚙️ Enable / Disable Test IDs
105
+
106
+ You can enable test IDs only in E2E environments:
107
+
108
+ ```js
109
+ const { configure } = require("e2e-testid");
110
+
111
+ configure({ enabled: true });
112
+ ```
113
+
114
+ Or automatically enable using environment variable:
115
+
116
+ ```bash
117
+ E2E=true
118
+ ```
119
+
120
+ This prevents `data-testid` from being included in production builds if desired.
121
+
122
+ ---
123
+
124
+ ## 🧠 Recommended Naming Convention
125
+
126
+ Use structured names:
127
+
128
+ ```
129
+ Feature.Screen.Element
130
+ ```
131
+
132
+ Examples:
133
+
134
+ ```
135
+ Auth.Login.EmailInput
136
+ Auth.Login.Submit
137
+ Cart.Checkout.Total
138
+ Checkout.Success.Message
139
+ ```
140
+
141
+ This keeps your test suite readable and scalable.
142
+
143
+ ---
144
+
145
+ ## 🎯 Works With
146
+
147
+ * Playwright
148
+ * Cypress
149
+ * Selenium
150
+ * Any E2E framework
151
+
152
+ ---
153
+
154
+ ## 📌 Example With Playwright
155
+
156
+ ```js
157
+ await page.getByTestId("Auth.Login.Submit").click();
158
+ ```
159
+
160
+ ---
161
+
162
+ ## 📄 License
163
+
164
+ ISC
165
+
166
+
package/index.js ADDED
@@ -0,0 +1,126 @@
1
+ const state = {
2
+ enabled: (() => {
3
+ const v =
4
+ (typeof process !== "undefined" &&
5
+ process.env &&
6
+ (process.env.E2E_TESTIDS || process.env.E2E || process.env.NODE_ENV)) ||
7
+ "";
8
+ const s = String(v).toLowerCase();
9
+ if (s === "1" || s === "true" || s === "yes" || s === "on") return true;
10
+ if (s === "test" || s === "e2e") return true;
11
+ return false;
12
+ })(),
13
+ attr: "data-testid",
14
+ sep: ".",
15
+ sanitizer: (x) =>
16
+ String(x)
17
+ .trim()
18
+ .replace(/\s+/g, "_")
19
+ .replace(/[^\w.\-:/]/g, "_")
20
+ .replace(/_+/g, "_")
21
+ .replace(/^_+|_+$/g, "")
22
+ };
23
+
24
+ function configure(options = {}) {
25
+ if (Object.prototype.hasOwnProperty.call(options, "enabled")) {
26
+ state.enabled = Boolean(options.enabled);
27
+ }
28
+ if (Object.prototype.hasOwnProperty.call(options, "attr") && options.attr) {
29
+ state.attr = String(options.attr);
30
+ }
31
+ if (Object.prototype.hasOwnProperty.call(options, "sep") && options.sep) {
32
+ state.sep = String(options.sep);
33
+ }
34
+ if (
35
+ Object.prototype.hasOwnProperty.call(options, "sanitizer") &&
36
+ typeof options.sanitizer === "function"
37
+ ) {
38
+ state.sanitizer = options.sanitizer;
39
+ }
40
+ return getConfig();
41
+ }
42
+
43
+ function getConfig() {
44
+ return { enabled: state.enabled, attr: state.attr, sep: state.sep };
45
+ }
46
+
47
+ function isEnabled() {
48
+ return state.enabled;
49
+ }
50
+
51
+ function normalizePart(part) {
52
+ if (part === null || part === undefined) return "";
53
+ const s = state.sanitizer(part);
54
+ return s;
55
+ }
56
+
57
+ function joinParts(parts) {
58
+ const out = [];
59
+ for (const p of parts) {
60
+ const n = normalizePart(p);
61
+ if (n) out.push(n);
62
+ }
63
+ return out.join(state.sep);
64
+ }
65
+
66
+ function ensureId(idOrParts) {
67
+ if (Array.isArray(idOrParts)) return joinParts(idOrParts);
68
+ return normalizePart(idOrParts);
69
+ }
70
+
71
+ function tid(id, extraProps) {
72
+ const props = extraProps && typeof extraProps === "object" ? extraProps : {};
73
+ if (!state.enabled) return props;
74
+ const testId = ensureId(id);
75
+ if (!testId) return props;
76
+ return { ...props, [state.attr]: testId };
77
+ }
78
+
79
+ function tidValue(id) {
80
+ const testId = ensureId(id);
81
+ return testId;
82
+ }
83
+
84
+ function createTid(namespace) {
85
+ const base = normalizePart(namespace);
86
+ const builder = (...parts) => joinParts([base, ...parts]);
87
+
88
+ builder.base = () => base;
89
+
90
+ builder.of = (...parts) => joinParts([base, ...parts]);
91
+
92
+ builder.tid = (...parts) => tid(joinParts([base, ...parts]));
93
+
94
+ builder.value = (...parts) => tidValue(joinParts([base, ...parts]));
95
+
96
+ builder.with = (parts, extraProps) =>
97
+ tid(
98
+ joinParts([base, ...(Array.isArray(parts) ? parts : [parts])]),
99
+ extraProps
100
+ );
101
+
102
+ builder.child = (childNamespace) => createTid(joinParts([base, childNamespace]));
103
+
104
+ builder.enable = () => configure({ enabled: true });
105
+
106
+ builder.disable = () => configure({ enabled: false });
107
+
108
+ return builder;
109
+ }
110
+
111
+ function makeJourneyTid(feature, screen) {
112
+ const f = normalizePart(feature);
113
+ const s = normalizePart(screen);
114
+ const t = createTid(joinParts([f, s]));
115
+ return t;
116
+ }
117
+
118
+ module.exports = {
119
+ configure,
120
+ getConfig,
121
+ isEnabled,
122
+ tid,
123
+ tidValue,
124
+ createTid,
125
+ makeJourneyTid
126
+ };
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "e2e-testid",
3
+ "version": "1.0.3",
4
+ "description": "A small utility for stable and consistent data-testid generation for E2E testing.",
5
+ "license": "ISC",
6
+ "author": "Taha Kourani",
7
+ "type": "commonjs",
8
+ "main": "index.js",
9
+ "exports": {
10
+ ".": "./index.js"
11
+ },
12
+ "keywords": [
13
+ "e2e",
14
+ "testing",
15
+ "testid",
16
+ "data-testid",
17
+ "playwright",
18
+ "cypress",
19
+ "selectors",
20
+ "react"
21
+ ],
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/TechTaha-lab/react-packages.git"
25
+ },
26
+ "bugs": {
27
+ "url": "https://github.com/TechTaha-lab/react-packages/issues"
28
+ },
29
+ "homepage": "https://github.com/TechTaha-lab/react-packages#readme",
30
+ "files": [
31
+ "index.js",
32
+ "README.md",
33
+ "LICENSE"
34
+ ],
35
+ "sideEffects": false,
36
+ "engines": {
37
+ "node": ">=14"
38
+ },
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "scripts": {
43
+ "test": "echo \"No tests yet\" && exit 0"
44
+ }
45
+ }