Skip to content

Commit 6fdb9af

Browse files
[javascript] Move atoms from closure to typescript
1 parent adf9028 commit 6fdb9af

44 files changed

Lines changed: 10730 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,331 @@
1+
# WebDriver Atoms TypeScript Migration - Detailed Analysis
2+
3+
## File Manifest with Metrics
4+
5+
| Phase | File | Lines | Status | Dependencies |
6+
|-------|------|-------|--------|--------------|
7+
| **Phase 1: Foundation** | | | | |
8+
| | webdriver.atoms.inject | ~50 | Blueprint | atoms-ts only |
9+
| **Phase 2: Storage** | | | | |
10+
| | storage/local_storage | 96 | Independent | None |
11+
| | storage/session_storage | 96 | Independent | None |
12+
| | storage/appcache | 36 | Independent | None |
13+
| **Phase 3: Core** | | | | |
14+
| | element | 281 | High value | bot.dom, bot.action |
15+
| | attribute | 192 | High value | bot.dom |
16+
| | inputs | 205 | High value | bot.action, element |
17+
| **Phase 4: Inject** | | | | |
18+
| | inject/execute_script | 83 | Medium | inject base |
19+
| | inject/appcache | 36 | Simple | storage.appcache |
20+
| | inject/sql_database | 57 | Simple | inject base |
21+
| | inject/frame | 98 | Medium | bot.dom |
22+
| | inject/find_element | 113 | Medium | bot.dom |
23+
| | inject/dom | 177 | Medium | bot.dom, element |
24+
| | inject/local_storage | 101 | Medium | storage.local_storage |
25+
| | inject/session_storage | 101 | Medium | storage.session_storage |
26+
| | inject/action | 249 | Complex | element, inputs |
27+
| **Phase 5: Export** | | | | |
28+
| | exports/inputs | 39 | Simple | inputs |
29+
| **TOTAL** | **16 files** | **~1960** | **100%** | **atoms-ts modules** |
30+
31+
## Dependency Matrix
32+
33+
```
34+
Legend:
35+
→ depends on
36+
◆ is blocked by (reverse dependency)
37+
```
38+
39+
### Initialization Order
40+
41+
```
42+
START
43+
44+
Phase 1: webdriver.atoms.inject (base module)
45+
↓ (unblocks all others)
46+
├─→ Phase 2: storage/* (3 parallel)
47+
│ ├─→ local_storage
48+
│ ├─→ session_storage
49+
│ └─→ appcache
50+
51+
├─→ Phase 3: core atoms (3 sequential)
52+
│ ├─→ attribute.ts (no dependencies on other webdriver atoms)
53+
│ ├─→ element.ts (no dependencies on other webdriver atoms)
54+
│ └─→ inputs.ts (can use element utilities)
55+
56+
└─→ Phase 4: inject/* (depends on Phase 2 + 3)
57+
├─→ Tier 1 (simple, no cross-dependencies):
58+
│ ├─→ execute_script
59+
│ ├─→ appcache (→ storage.appcache)
60+
│ └─→ sql_database
61+
62+
├─→ Tier 2 (medium):
63+
│ ├─→ frame
64+
│ ├─→ find_element
65+
│ └─→ dom (can use element utilities)
66+
67+
├─→ Tier 3 (storage wrappers):
68+
│ ├─→ local_storage (→ storage.local_storage)
69+
│ └─→ session_storage (→ storage.session_storage)
70+
71+
└─→ Tier 4 (complex):
72+
└─→ action (→ element, inputs)
73+
74+
Phase 5: exports/* (final wrappers)
75+
└─→ exports/inputs (→ inputs)
76+
77+
END (All modules compiled)
78+
```
79+
80+
## Closure to TypeScript Conversion Patterns
81+
82+
### Pattern 1: Namespace to Module Export
83+
84+
**Before (Closure):**
85+
86+
```javascript
87+
goog.provide('webdriver.atoms.element');
88+
goog.require('bot.dom');
89+
90+
webdriver.atoms.element.isDisplayed = function(element) {
91+
return bot.dom.isShown(element);
92+
};
93+
94+
webdriver.atoms.element.getAttribute = function(element, name) {
95+
return element.getAttribute(name);
96+
};
97+
```
98+
99+
**After (TypeScript):**
100+
101+
```typescript
102+
import * as dom from '../../atoms-ts/src/dom';
103+
104+
export function isDisplayed(element: Element): boolean {
105+
return dom.isShown(element);
106+
}
107+
108+
export function getAttribute(element: Element, name: string): string | null {
109+
return element.getAttribute(name);
110+
}
111+
```
112+
113+
### Pattern 2: Object to Class Conversion
114+
115+
**Before (Closure):**
116+
117+
```javascript
118+
webdriver.atoms.element.Size = function(width, height) {
119+
this.width = width;
120+
this.height = height;
121+
};
122+
```
123+
124+
**After (TypeScript):**
125+
126+
```typescript
127+
export interface Size {
128+
width: number;
129+
height: number;
130+
}
131+
132+
export function getSize(element: Element): Size {
133+
const rect = element.getBoundingClientRect();
134+
return { width: rect.width, height: rect.height };
135+
}
136+
```
137+
138+
### Pattern 3: Script Injection Conversion
139+
140+
**Before (Closure):**
141+
142+
```javascript
143+
goog.provide('webdriver.atoms.inject.action');
144+
goog.require('bot.action');
145+
146+
webdriver.atoms.inject.action = {};
147+
webdriver.atoms.inject.action.click = function(element) {
148+
return bot.action.click(element);
149+
};
150+
```
151+
152+
**After (TypeScript):**
153+
154+
```typescript
155+
import * as action from '../../atoms-ts/src/action';
156+
import { injectScript } from './inject';
157+
158+
export function click(element: Element): void {
159+
return injectScript(() => {
160+
return action.click(element);
161+
});
162+
}
163+
```
164+
165+
### Pattern 4: JSON Serialization
166+
167+
**Before (Closure):**
168+
169+
```javascript
170+
goog.require('goog.json');
171+
goog.json.serialize(result);
172+
```
173+
174+
**After (TypeScript):**
175+
176+
```typescript
177+
JSON.stringify(result); // Native JSON API
178+
```
179+
180+
### Pattern 5: Array Iteration
181+
182+
**Before (Closure):**
183+
184+
```javascript
185+
goog.require('goog.array');
186+
goog.array.forEach(elements, function(elem) {
187+
return elem.getAttribute('name');
188+
});
189+
```
190+
191+
**After (TypeScript):**
192+
193+
```typescript
194+
elements.forEach((elem: Element) => {
195+
return elem.getAttribute('name');
196+
});
197+
// or map:
198+
elements.map((elem: Element) => elem.getAttribute('name'));
199+
```
200+
201+
## Critical Implementation Notes
202+
203+
### For inject/action.ts
204+
205+
The action injection module is the most complex because it:
206+
207+
1. Bridges between webdriver elements and bot.action functions
208+
2. Handles coordinate translation
209+
3. Manages element state during actions
210+
4. Supports multiple browser event types
211+
212+
**Key considerations:**
213+
214+
- Must handle MSPointerEvent for IE10 (already done in bot atoms)
215+
- Must coordinate with touchscreen for mobile
216+
- Must preserve event ordering
217+
218+
### For element.ts
219+
220+
The element module is a bridge between WebDriver and bot DOM functions:
221+
222+
1. Size calculation (must handle transform matrices)
223+
2. Visibility detection (uses bot.dom.isShown with opacity handling)
224+
3. Attribute access (must handle HTML attributes vs DOM properties)
225+
4. CSS property access (must use getComputedStyle)
226+
227+
**Key considerations:**
228+
229+
- CSS property names can differ from JavaScript property names
230+
- Some properties are read-only
231+
- Must handle pseudo-elements separately
232+
233+
### For storage/* modules
234+
235+
These are the simplest because they directly wrap Web Storage APIs:
236+
237+
- No Closure Library usage
238+
- No bot module dependencies
239+
- Simple try-catch error handling for cross-origin issues
240+
241+
**Key considerations:**
242+
243+
- sessionStorage and localStorage throw on private browsing in some browsers
244+
- AppCache is deprecated, but still in use in some Selenium tests
245+
- Must handle QuotaExceededError
246+
247+
## Testing Strategy
248+
249+
### Unit Tests
250+
251+
- Each module tested in isolation
252+
- Mock element/DOM as needed
253+
- Test browser compatibility variations
254+
255+
### Integration Tests
256+
257+
- Test inject modules calling through to bot modules
258+
- Test element operations on real DOM
259+
- Test storage operations in different contexts
260+
261+
### Cross-Browser Tests
262+
263+
- IE11 (if still supported)
264+
- Firefox latest
265+
- Chrome latest
266+
- Safari latest
267+
- Edge (Chromium-based)
268+
269+
## Configuration Files Needed
270+
271+
### tsconfig.json (if not inherited)
272+
273+
```json
274+
{
275+
"compilerOptions": {
276+
"target": "ES2020",
277+
"module": "ES2020",
278+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
279+
"declaration": true,
280+
"strict": true
281+
}
282+
}
283+
```
284+
285+
### BUILD.bazel Template
286+
287+
```bazel
288+
load("//common:defs.bzl", "ts_project")
289+
290+
ts_project(
291+
name = "module_name",
292+
srcs = ["module_name.ts"],
293+
declaration = True,
294+
declaration_map = True,
295+
resolve_json_module = True,
296+
source_map = True,
297+
tsconfig = "tsconfig.json",
298+
deps = [
299+
"//javascript/atoms-ts/src:module_dep",
300+
# other internal deps
301+
],
302+
visibility = ["//javascript:__subpackages__"],
303+
)
304+
```
305+
306+
## Success Metrics
307+
308+
### Build Metrics
309+
310+
- ✅ All 16 modules compile without errors
311+
- ✅ Zero TypeScript strict mode violations
312+
- ✅ All type definitions properly inferred or explicit
313+
- ✅ Source maps generated correctly
314+
315+
### API Metrics
316+
317+
- ✅ 100% of public functions exported
318+
- ✅ All function signatures match original
319+
- ✅ All return types compatible with original
320+
321+
### Code Quality Metrics
322+
323+
- ✅ No `any` types in critical paths (max 5%)
324+
- ✅ JSDoc comments converted to TypeScript
325+
- ✅ Consistent naming conventions
326+
327+
### Coverage Metrics
328+
329+
- ✅ All critical paths tested
330+
- ✅ Browser compatibility verified
331+
- ✅ Integration tests passing

0 commit comments

Comments
 (0)