@maccesar/titools 2.0.7 → 2.2.1
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/AGENTS-VERCEL-RESEARCH.md +172 -0
- package/README.md +408 -389
- package/agents/{ti-researcher.md → ti-pro.md} +14 -13
- package/bin/titools.js +16 -12
- package/lib/cleanup.js +95 -0
- package/lib/commands/agents.js +146 -70
- package/lib/commands/skills.js +349 -0
- package/lib/commands/uninstall.js +189 -154
- package/lib/commands/update.js +104 -21
- package/lib/config.js +26 -20
- package/lib/downloader.js +1 -1
- package/lib/installer.js +37 -97
- package/lib/platform.js +9 -5
- package/lib/prompts/checkboxCancel.js +264 -0
- package/lib/prompts/selectCancel.js +204 -0
- package/lib/symlink.js +19 -7
- package/lib/utils.js +17 -17
- package/package.json +10 -10
- package/skills/alloy-guides/SKILL.md +8 -30
- package/skills/alloy-guides/references/CLI_TASKS.md +14 -24
- package/skills/alloy-guides/references/CONCEPTS.md +5 -25
- package/skills/alloy-guides/references/CONTROLLERS.md +2 -19
- package/skills/alloy-guides/references/MODELS.md +40 -10
- package/skills/alloy-guides/references/PURGETSS.md +1 -11
- package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +8 -14
- package/skills/alloy-guides/references/VIEWS_STYLES.md +14 -25
- package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +2 -8
- package/skills/alloy-guides/references/VIEWS_XML.md +29 -40
- package/skills/alloy-guides/references/WIDGETS.md +1 -17
- package/skills/alloy-howtos/SKILL.md +1 -22
- package/skills/alloy-howtos/references/best_practices.md +0 -17
- package/skills/alloy-howtos/references/cli_reference.md +1 -23
- package/skills/alloy-howtos/references/config_files.md +86 -15
- package/skills/alloy-howtos/references/custom_tags.md +14 -13
- package/skills/alloy-howtos/references/debugging_troubleshooting.md +3 -22
- package/skills/alloy-howtos/references/samples.md +4 -14
- package/skills/purgetss/SKILL.md +11 -37
- package/skills/purgetss/references/EXAMPLES.md +106 -17
- package/skills/purgetss/references/animation-system.md +0 -67
- package/skills/purgetss/references/apply-directive.md +0 -18
- package/skills/purgetss/references/arbitrary-values.md +0 -25
- package/skills/purgetss/references/class-index.md +0 -46
- package/skills/purgetss/references/cli-commands.md +0 -41
- package/skills/purgetss/references/configurable-properties.md +0 -55
- package/skills/purgetss/references/custom-rules.md +0 -14
- package/skills/purgetss/references/customization-deep-dive.md +0 -49
- package/skills/purgetss/references/dynamic-component-creation.md +56 -37
- package/skills/purgetss/references/grid-layout.md +0 -32
- package/skills/purgetss/references/icon-fonts.md +0 -50
- package/skills/purgetss/references/installation-setup.md +61 -32
- package/skills/purgetss/references/migration-guide.md +127 -0
- package/skills/purgetss/references/opacity-modifier.md +0 -34
- package/skills/purgetss/references/performance-tips.md +261 -0
- package/skills/purgetss/references/platform-modifiers.md +0 -46
- package/skills/purgetss/references/smart-mappings.md +0 -12
- package/skills/purgetss/references/tikit-components.md +393 -0
- package/skills/purgetss/references/titanium-resets.md +1 -27
- package/skills/purgetss/references/ui-ux-design.md +467 -117
- package/skills/{alloy-expert → ti-expert}/SKILL.md +45 -54
- package/skills/ti-expert/references/alloy-builtins.md +387 -0
- package/skills/{alloy-expert → ti-expert}/references/alloy-structure.md +147 -40
- package/skills/ti-expert/references/anti-patterns.md +90 -0
- package/skills/ti-expert/references/cli-expert.md +109 -0
- package/skills/{alloy-expert → ti-expert}/references/code-conventions.md +182 -49
- package/skills/{alloy-expert → ti-expert}/references/controller-patterns.md +103 -93
- package/skills/{alloy-expert → ti-expert}/references/error-handling.md +12 -12
- package/skills/{alloy-expert → ti-expert}/references/examples.md +144 -85
- package/skills/{alloy-expert → ti-expert}/references/migration-patterns.md +38 -36
- package/skills/{alloy-expert → ti-expert}/references/patterns.md +8 -8
- package/skills/ti-expert/references/performance-listview.md +251 -0
- package/skills/{alloy-expert/references/performance-patterns.md → ti-expert/references/performance-optimization.md} +67 -283
- package/skills/{alloy-expert/references/security-patterns.md → ti-expert/references/security-device.md} +12 -295
- package/skills/ti-expert/references/security-fundamentals.md +284 -0
- package/skills/{alloy-expert → ti-expert}/references/state-management.md +10 -10
- package/skills/ti-expert/references/testing-e2e-ci.md +432 -0
- package/skills/ti-expert/references/testing-unit.md +433 -0
- package/skills/ti-expert/references/theming.md +394 -0
- package/skills/ti-guides/SKILL.md +1 -14
- package/skills/ti-guides/references/advanced-data-and-images.md +126 -10
- package/skills/ti-guides/references/app-distribution.md +48 -10
- package/skills/ti-guides/references/application-frameworks.md +9 -2
- package/skills/ti-guides/references/cli-reference.md +338 -82
- package/skills/ti-guides/references/coding-best-practices.md +14 -4
- package/skills/ti-guides/references/commonjs-advanced.md +103 -6
- package/skills/ti-guides/references/hello-world.md +5 -2
- package/skills/ti-guides/references/hyperloop-native-access.md +439 -46
- package/skills/ti-guides/references/javascript-primer.md +4 -3
- package/skills/ti-guides/references/resources.md +0 -1
- package/skills/ti-guides/references/style-and-conventions.md +57 -9
- package/skills/ti-guides/references/tiapp-config.md +48 -6
- package/skills/ti-howtos/SKILL.md +2 -27
- package/skills/ti-howtos/references/android-platform-deep-dives.md +41 -90
- package/skills/ti-howtos/references/automation-fastlane-appium.md +15 -14
- package/skills/ti-howtos/references/buffer-codec-streams.md +22 -22
- package/skills/ti-howtos/references/cross-platform-development.md +68 -37
- package/skills/ti-howtos/references/debugging-profiling.md +8 -53
- package/skills/ti-howtos/references/extending-titanium.md +12 -51
- package/skills/ti-howtos/references/google-maps-v2.md +30 -29
- package/skills/ti-howtos/references/ios-map-kit.md +19 -25
- package/skills/ti-howtos/references/ios-platform-deep-dives.md +95 -283
- package/skills/ti-howtos/references/local-data-sources.md +45 -37
- package/skills/ti-howtos/references/location-and-maps.md +47 -28
- package/skills/ti-howtos/references/media-apis.md +84 -27
- package/skills/ti-howtos/references/notification-services.md +40 -89
- package/skills/ti-howtos/references/remote-data-sources.md +21 -36
- package/skills/ti-howtos/references/tutorials.md +79 -39
- package/skills/ti-howtos/references/using-modules.md +4 -30
- package/skills/ti-howtos/references/web-content-integration.md +28 -45
- package/skills/ti-howtos/references/webpack-build-pipeline.md +54 -18
- package/skills/ti-ui/SKILL.md +1 -21
- package/skills/ti-ui/references/accessibility-deep-dive.md +71 -25
- package/skills/ti-ui/references/animation-and-matrices.md +0 -47
- package/skills/ti-ui/references/application-structures.md +0 -46
- package/skills/ti-ui/references/custom-fonts-styling.md +9 -57
- package/skills/ti-ui/references/event-handling.md +32 -40
- package/skills/ti-ui/references/gestures.md +0 -40
- package/skills/ti-ui/references/icons-and-splash-screens.md +21 -44
- package/skills/ti-ui/references/layouts-and-positioning.md +47 -39
- package/skills/ti-ui/references/listviews-and-performance.md +187 -73
- package/skills/ti-ui/references/orientation.md +57 -71
- package/skills/ti-ui/references/platform-ui-android.md +114 -48
- package/skills/ti-ui/references/platform-ui-ios.md +63 -38
- package/skills/ti-ui/references/scrolling-views.md +14 -23
- package/skills/ti-ui/references/tableviews.md +6 -56
- package/AGENTS-TEMPLATE.md +0 -174
- package/lib/commands/install.js +0 -188
- package/skills/alloy-expert/references/anti-patterns.md +0 -133
- package/skills/alloy-expert/references/testing.md +0 -872
- package/skills/ti-guides/references/alloy-cli-advanced.md +0 -84
- package/skills/ti-guides/references/alloy-data-mastery.md +0 -29
- package/skills/ti-guides/references/alloy-widgets-and-themes.md +0 -19
- /package/skills/{alloy-expert → ti-expert}/assets/ControllerAutoCleanup.js +0 -0
- /package/skills/{alloy-expert → ti-expert}/references/contracts.md +0 -0
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
# End-to-End Testing & CI/CD
|
|
2
|
+
|
|
3
|
+
## Appium Setup
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
# Install Appium
|
|
7
|
+
npm install -g appium
|
|
8
|
+
|
|
9
|
+
# Install drivers
|
|
10
|
+
appium driver install xcuitest # iOS
|
|
11
|
+
appium driver install uiautomator2 # Android
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Appium Configuration
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
// e2e/config/capabilities.js
|
|
18
|
+
exports.iOS = {
|
|
19
|
+
platformName: 'iOS',
|
|
20
|
+
'appium:automationName': 'XCUITest',
|
|
21
|
+
'appium:deviceName': 'iPhone 14',
|
|
22
|
+
'appium:platformVersion': '16.0',
|
|
23
|
+
'appium:app': '/path/to/your.app',
|
|
24
|
+
'appium:noReset': false
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
exports.android = {
|
|
28
|
+
platformName: 'Android',
|
|
29
|
+
'appium:automationName': 'UiAutomator2',
|
|
30
|
+
'appium:deviceName': 'Pixel 6',
|
|
31
|
+
'appium:platformVersion': '13',
|
|
32
|
+
'appium:app': '/path/to/your.apk',
|
|
33
|
+
'appium:noReset': false
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## WebdriverIO Integration
|
|
38
|
+
|
|
39
|
+
```javascript
|
|
40
|
+
// e2e/wdio.conf.js
|
|
41
|
+
exports.config = {
|
|
42
|
+
runner: 'local',
|
|
43
|
+
specs: ['./e2e/specs/**/*.spec.js'],
|
|
44
|
+
maxInstances: 1,
|
|
45
|
+
|
|
46
|
+
capabilities: [{
|
|
47
|
+
...require('./config/capabilities').iOS
|
|
48
|
+
}],
|
|
49
|
+
|
|
50
|
+
services: ['appium'],
|
|
51
|
+
appium: {
|
|
52
|
+
command: 'appium'
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
framework: 'mocha',
|
|
56
|
+
mochaOpts: {
|
|
57
|
+
timeout: 60000
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
reporters: ['spec'],
|
|
61
|
+
|
|
62
|
+
// Hooks
|
|
63
|
+
beforeSession: () => {
|
|
64
|
+
// Setup before each session
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
afterTest: async (test, context, { passed }) => {
|
|
68
|
+
if (!passed) {
|
|
69
|
+
await browser.saveScreenshot(`./e2e/screenshots/${test.title}.png`)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## E2E Test Example
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
// e2e/specs/login.spec.js
|
|
79
|
+
describe('Login Flow', () => {
|
|
80
|
+
beforeEach(async () => {
|
|
81
|
+
// Ensure we're on login screen
|
|
82
|
+
await $('~loginScreen').waitForDisplayed({ timeout: 5000 })
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('should login with valid credentials', async () => {
|
|
86
|
+
// Enter email
|
|
87
|
+
const emailField = await $('~emailField')
|
|
88
|
+
await emailField.setValue('test@example.com')
|
|
89
|
+
|
|
90
|
+
// Enter password
|
|
91
|
+
const passwordField = await $('~passwordField')
|
|
92
|
+
await passwordField.setValue('password123')
|
|
93
|
+
|
|
94
|
+
// Tap login button
|
|
95
|
+
const loginButton = await $('~loginButton')
|
|
96
|
+
await loginButton.click()
|
|
97
|
+
|
|
98
|
+
// Wait for home screen
|
|
99
|
+
const homeScreen = await $('~homeScreen')
|
|
100
|
+
await homeScreen.waitForDisplayed({ timeout: 10000 })
|
|
101
|
+
|
|
102
|
+
// Verify we're logged in
|
|
103
|
+
const welcomeLabel = await $('~welcomeLabel')
|
|
104
|
+
const text = await welcomeLabel.getText()
|
|
105
|
+
expect(text).toContain('Welcome')
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('should show error for invalid credentials', async () => {
|
|
109
|
+
const emailField = await $('~emailField')
|
|
110
|
+
await emailField.setValue('wrong@example.com')
|
|
111
|
+
|
|
112
|
+
const passwordField = await $('~passwordField')
|
|
113
|
+
await passwordField.setValue('wrongpassword')
|
|
114
|
+
|
|
115
|
+
const loginButton = await $('~loginButton')
|
|
116
|
+
await loginButton.click()
|
|
117
|
+
|
|
118
|
+
// Wait for error message
|
|
119
|
+
const errorLabel = await $('~errorLabel')
|
|
120
|
+
await errorLabel.waitForDisplayed({ timeout: 5000 })
|
|
121
|
+
|
|
122
|
+
const errorText = await errorLabel.getText()
|
|
123
|
+
expect(errorText).toContain('Invalid')
|
|
124
|
+
})
|
|
125
|
+
})
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Adding Accessibility IDs for Testing
|
|
129
|
+
|
|
130
|
+
```xml
|
|
131
|
+
<!-- views/auth/login.xml -->
|
|
132
|
+
<Window testId="loginScreen">
|
|
133
|
+
<TextField id="emailField" testId="emailField" />
|
|
134
|
+
<TextField id="passwordField" testId="passwordField" />
|
|
135
|
+
<Button id="loginBtn" testId="loginButton" />
|
|
136
|
+
<Label id="errorLabel" testId="errorLabel" />
|
|
137
|
+
</Window>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
```javascript
|
|
141
|
+
// In controller or alloy.js - map testId to accessibilityLabel
|
|
142
|
+
if (Alloy.CFG.debug) {
|
|
143
|
+
// Auto-set accessibilityLabel from testId during development
|
|
144
|
+
Ti.UI.defaultUnit = 'dp'
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Page Object Pattern
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
// e2e/pages/LoginPage.js
|
|
152
|
+
class LoginPage {
|
|
153
|
+
get emailField() { return $('~emailField') }
|
|
154
|
+
get passwordField() { return $('~passwordField') }
|
|
155
|
+
get loginButton() { return $('~loginButton') }
|
|
156
|
+
get errorLabel() { return $('~errorLabel') }
|
|
157
|
+
|
|
158
|
+
async login(email, password) {
|
|
159
|
+
await this.emailField.setValue(email)
|
|
160
|
+
await this.passwordField.setValue(password)
|
|
161
|
+
await this.loginButton.click()
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async waitForError() {
|
|
165
|
+
await this.errorLabel.waitForDisplayed({ timeout: 5000 })
|
|
166
|
+
return this.errorLabel.getText()
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
module.exports = new LoginPage()
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
```javascript
|
|
174
|
+
// e2e/specs/login.spec.js
|
|
175
|
+
const LoginPage = require('../pages/LoginPage')
|
|
176
|
+
const HomePage = require('../pages/HomePage')
|
|
177
|
+
|
|
178
|
+
describe('Login Flow', () => {
|
|
179
|
+
it('should login successfully', async () => {
|
|
180
|
+
await LoginPage.login('test@example.com', 'password123')
|
|
181
|
+
await HomePage.waitForDisplayed()
|
|
182
|
+
expect(await HomePage.isLoggedIn()).toBe(true)
|
|
183
|
+
})
|
|
184
|
+
})
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## CI/CD Integration
|
|
188
|
+
|
|
189
|
+
### GitHub Actions Workflow
|
|
190
|
+
|
|
191
|
+
```yaml
|
|
192
|
+
# .github/workflows/ci.yml
|
|
193
|
+
name: CI
|
|
194
|
+
|
|
195
|
+
on:
|
|
196
|
+
push:
|
|
197
|
+
branches: [main, develop]
|
|
198
|
+
pull_request:
|
|
199
|
+
branches: [main]
|
|
200
|
+
|
|
201
|
+
jobs:
|
|
202
|
+
lint:
|
|
203
|
+
runs-on: ubuntu-latest
|
|
204
|
+
steps:
|
|
205
|
+
- uses: actions/checkout@v3
|
|
206
|
+
|
|
207
|
+
- name: Setup Node.js
|
|
208
|
+
uses: actions/setup-node@v3
|
|
209
|
+
with:
|
|
210
|
+
node-version: '18'
|
|
211
|
+
cache: 'npm'
|
|
212
|
+
|
|
213
|
+
- name: Install dependencies
|
|
214
|
+
run: npm ci
|
|
215
|
+
|
|
216
|
+
- name: Run ESLint
|
|
217
|
+
run: npm run lint
|
|
218
|
+
|
|
219
|
+
unit-tests:
|
|
220
|
+
runs-on: ubuntu-latest
|
|
221
|
+
needs: lint
|
|
222
|
+
steps:
|
|
223
|
+
- uses: actions/checkout@v3
|
|
224
|
+
|
|
225
|
+
- name: Setup Node.js
|
|
226
|
+
uses: actions/setup-node@v3
|
|
227
|
+
with:
|
|
228
|
+
node-version: '18'
|
|
229
|
+
|
|
230
|
+
- name: Install dependencies
|
|
231
|
+
run: npm ci
|
|
232
|
+
|
|
233
|
+
- name: Run unit tests
|
|
234
|
+
run: npm run test:unit
|
|
235
|
+
|
|
236
|
+
- name: Upload coverage
|
|
237
|
+
uses: codecov/codecov-action@v3
|
|
238
|
+
with:
|
|
239
|
+
files: ./coverage/lcov.info
|
|
240
|
+
|
|
241
|
+
build-ios:
|
|
242
|
+
runs-on: macos-latest
|
|
243
|
+
needs: unit-tests
|
|
244
|
+
steps:
|
|
245
|
+
- uses: actions/checkout@v3
|
|
246
|
+
|
|
247
|
+
- name: Setup Node.js
|
|
248
|
+
uses: actions/setup-node@v3
|
|
249
|
+
with:
|
|
250
|
+
node-version: '18'
|
|
251
|
+
|
|
252
|
+
- name: Install Titanium CLI
|
|
253
|
+
run: npm install -g titanium alloy
|
|
254
|
+
|
|
255
|
+
- name: Setup Titanium SDK
|
|
256
|
+
run: |
|
|
257
|
+
titanium sdk install latest
|
|
258
|
+
titanium sdk select latest
|
|
259
|
+
|
|
260
|
+
- name: Install dependencies
|
|
261
|
+
run: npm ci
|
|
262
|
+
|
|
263
|
+
- name: Build iOS
|
|
264
|
+
run: titanium build -p ios -T simulator -b
|
|
265
|
+
|
|
266
|
+
- name: Upload artifact
|
|
267
|
+
uses: actions/upload-artifact@v3
|
|
268
|
+
with:
|
|
269
|
+
name: ios-build
|
|
270
|
+
path: build/iphone/build/Products/Debug-iphonesimulator/*.app
|
|
271
|
+
|
|
272
|
+
build-android:
|
|
273
|
+
runs-on: ubuntu-latest
|
|
274
|
+
needs: unit-tests
|
|
275
|
+
steps:
|
|
276
|
+
- uses: actions/checkout@v3
|
|
277
|
+
|
|
278
|
+
- name: Setup JDK
|
|
279
|
+
uses: actions/setup-java@v3
|
|
280
|
+
with:
|
|
281
|
+
java-version: '11'
|
|
282
|
+
distribution: 'temurin'
|
|
283
|
+
|
|
284
|
+
- name: Setup Android SDK
|
|
285
|
+
uses: android-actions/setup-android@v2
|
|
286
|
+
|
|
287
|
+
- name: Setup Node.js
|
|
288
|
+
uses: actions/setup-node@v3
|
|
289
|
+
with:
|
|
290
|
+
node-version: '18'
|
|
291
|
+
|
|
292
|
+
- name: Install Titanium CLI
|
|
293
|
+
run: npm install -g titanium alloy
|
|
294
|
+
|
|
295
|
+
- name: Setup Titanium SDK
|
|
296
|
+
run: |
|
|
297
|
+
titanium sdk install latest
|
|
298
|
+
titanium sdk select latest
|
|
299
|
+
|
|
300
|
+
- name: Install dependencies
|
|
301
|
+
run: npm ci
|
|
302
|
+
|
|
303
|
+
- name: Build Android
|
|
304
|
+
run: titanium build -p android -T dist-playstore -K ${{ secrets.KEYSTORE_PATH }} -P ${{ secrets.KEYSTORE_PASSWORD }}
|
|
305
|
+
|
|
306
|
+
- name: Upload artifact
|
|
307
|
+
uses: actions/upload-artifact@v3
|
|
308
|
+
with:
|
|
309
|
+
name: android-build
|
|
310
|
+
path: dist/*.apk
|
|
311
|
+
|
|
312
|
+
e2e-tests:
|
|
313
|
+
runs-on: macos-latest
|
|
314
|
+
needs: [build-ios]
|
|
315
|
+
steps:
|
|
316
|
+
- uses: actions/checkout@v3
|
|
317
|
+
|
|
318
|
+
- name: Download iOS build
|
|
319
|
+
uses: actions/download-artifact@v3
|
|
320
|
+
with:
|
|
321
|
+
name: ios-build
|
|
322
|
+
path: ./build
|
|
323
|
+
|
|
324
|
+
- name: Setup Node.js
|
|
325
|
+
uses: actions/setup-node@v3
|
|
326
|
+
with:
|
|
327
|
+
node-version: '18'
|
|
328
|
+
|
|
329
|
+
- name: Install Appium
|
|
330
|
+
run: |
|
|
331
|
+
npm install -g appium
|
|
332
|
+
appium driver install xcuitest
|
|
333
|
+
|
|
334
|
+
- name: Install test dependencies
|
|
335
|
+
run: cd e2e && npm ci
|
|
336
|
+
|
|
337
|
+
- name: Start Appium
|
|
338
|
+
run: appium &
|
|
339
|
+
|
|
340
|
+
- name: Run E2E tests
|
|
341
|
+
run: cd e2e && npm run test
|
|
342
|
+
|
|
343
|
+
- name: Upload screenshots
|
|
344
|
+
if: failure()
|
|
345
|
+
uses: actions/upload-artifact@v3
|
|
346
|
+
with:
|
|
347
|
+
name: e2e-screenshots
|
|
348
|
+
path: e2e/screenshots/
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## Fastlane Integration
|
|
352
|
+
|
|
353
|
+
```ruby
|
|
354
|
+
# fastlane/Fastfile
|
|
355
|
+
default_platform(:ios)
|
|
356
|
+
|
|
357
|
+
platform :ios do
|
|
358
|
+
desc "Build and upload to TestFlight"
|
|
359
|
+
lane :beta do
|
|
360
|
+
# Build with Titanium
|
|
361
|
+
sh "cd .. && titanium build -p ios -T dist-adhoc"
|
|
362
|
+
|
|
363
|
+
# Upload to TestFlight
|
|
364
|
+
upload_to_testflight(
|
|
365
|
+
ipa: "../dist/MyApp.ipa",
|
|
366
|
+
skip_waiting_for_build_processing: true
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
# Notify team
|
|
370
|
+
slack(
|
|
371
|
+
message: "New iOS beta available on TestFlight!",
|
|
372
|
+
channel: "#releases"
|
|
373
|
+
)
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
platform :android do
|
|
378
|
+
desc "Build and upload to Play Store"
|
|
379
|
+
lane :beta do
|
|
380
|
+
# Build with Titanium
|
|
381
|
+
sh "cd .. && titanium build -p android -T dist-playstore -K keystore.jks -P $KEYSTORE_PASSWORD"
|
|
382
|
+
|
|
383
|
+
# Upload to Play Store
|
|
384
|
+
upload_to_play_store(
|
|
385
|
+
track: 'internal',
|
|
386
|
+
aab: '../dist/MyApp.aab'
|
|
387
|
+
)
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
## Package.json Scripts
|
|
393
|
+
|
|
394
|
+
```json
|
|
395
|
+
{
|
|
396
|
+
"scripts": {
|
|
397
|
+
"lint": "eslint app/",
|
|
398
|
+
"test:unit": "titanium test --platform ios",
|
|
399
|
+
"test:e2e": "cd e2e && wdio run wdio.conf.js",
|
|
400
|
+
"test:e2e:android": "cd e2e && wdio run wdio.android.conf.js",
|
|
401
|
+
"build:ios": "titanium build -p ios -T device",
|
|
402
|
+
"build:android": "titanium build -p android -T device",
|
|
403
|
+
"build:ios:prod": "titanium build -p ios -T dist-appstore",
|
|
404
|
+
"build:android:prod": "titanium build -p android -T dist-playstore",
|
|
405
|
+
"deploy:ios": "cd fastlane && fastlane ios beta",
|
|
406
|
+
"deploy:android": "cd fastlane && fastlane android beta"
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
## Branch Protection Rules
|
|
412
|
+
|
|
413
|
+
Configure in GitHub repository settings:
|
|
414
|
+
|
|
415
|
+
| Rule | Setting |
|
|
416
|
+
| --------------------------------- | ------------------------------------------ |
|
|
417
|
+
| Require pull request reviews | 1 approval required |
|
|
418
|
+
| Require status checks | lint, unit-tests, build-ios, build-android |
|
|
419
|
+
| Require branches to be up to date | Yes |
|
|
420
|
+
| Include administrators | Yes |
|
|
421
|
+
|
|
422
|
+
## Testing Best Practices Summary
|
|
423
|
+
|
|
424
|
+
| Area | Practice |
|
|
425
|
+
| --------------------- | ------------------------------------------ |
|
|
426
|
+
| **Unit Tests** | Test business logic in services/helpers |
|
|
427
|
+
| **Integration Tests** | Test controller flows with mocked services |
|
|
428
|
+
| **E2E Tests** | Test critical user journeys |
|
|
429
|
+
| **Coverage** | Aim for 80%+ on services, 60%+ overall |
|
|
430
|
+
| **CI Pipeline** | Run lint -> unit tests -> build -> E2E |
|
|
431
|
+
| **Artifacts** | Save screenshots on failure |
|
|
432
|
+
| **Notifications** | Slack/email on build failures |
|