$npx -y skills add LambdaTest/agent-skills --skill protractor-skillGenerates Protractor E2E tests for Angular/AngularJS apps in JS/TS. NOTE: Protractor is officially deprecated — recommend Playwright or Cypress. Use when user mentions "Protractor", "element(by.model())", "Angular E2E". Triggers on: "Protractor", "element(by.model)", "Angular E2E
| 1 | # Protractor Automation Skill (Deprecated) |
| 2 | |
| 3 | > **Protractor reached end-of-life in 2023.** Angular team recommends Playwright or Cypress. |
| 4 | |
| 5 | For TestMu AI cloud execution, see [reference/cloud-integration.md](reference/cloud-integration.md) and [shared/testmu-cloud-reference.md](../shared/testmu-cloud-reference.md). |
| 6 | |
| 7 | ## Core Patterns |
| 8 | |
| 9 | ### Basic Test |
| 10 | |
| 11 | ```javascript |
| 12 | describe('Login', () => { |
| 13 | beforeEach(async () => { |
| 14 | await browser.get('/login'); |
| 15 | }); |
| 16 | |
| 17 | it('should login with valid credentials', async () => { |
| 18 | await element(by.model('email')).sendKeys('user@test.com'); |
| 19 | await element(by.model('password')).sendKeys('password123'); |
| 20 | await element(by.css('button[type="submit"]')).click(); |
| 21 | expect(await browser.getCurrentUrl()).toContain('/dashboard'); |
| 22 | expect(await element(by.css('.welcome')).getText()).toContain('Welcome'); |
| 23 | }); |
| 24 | |
| 25 | it('should show error for invalid credentials', async () => { |
| 26 | await element(by.model('email')).sendKeys('wrong@test.com'); |
| 27 | await element(by.model('password')).sendKeys('wrong'); |
| 28 | await element(by.css('button[type="submit"]')).click(); |
| 29 | expect(await element(by.css('.error')).isDisplayed()).toBe(true); |
| 30 | }); |
| 31 | }); |
| 32 | ``` |
| 33 | |
| 34 | ### Angular-Specific Locators |
| 35 | |
| 36 | ```javascript |
| 37 | element(by.model('ctrl.email')); // ng-model |
| 38 | element(by.binding('ctrl.username')); // Angular binding |
| 39 | element(by.exactBinding('ctrl.name')); // Exact binding |
| 40 | element(by.repeater('item in items')); // ng-repeat |
| 41 | element.all(by.repeater('item in items')).count(); // Count repeater |
| 42 | element(by.cssContainingText('.item', 'Active')); // CSS + text |
| 43 | element(by.buttonText('Submit')); // Button text |
| 44 | element(by.partialButtonText('Sub')); // Partial text |
| 45 | ``` |
| 46 | |
| 47 | ### Page Objects |
| 48 | |
| 49 | ```javascript |
| 50 | class LoginPage { |
| 51 | constructor() { |
| 52 | this.emailInput = element(by.model('email')); |
| 53 | this.passwordInput = element(by.model('password')); |
| 54 | this.loginButton = element(by.css('button[type="submit"]')); |
| 55 | this.errorMessage = element(by.css('.error')); |
| 56 | } |
| 57 | |
| 58 | async login(email, password) { |
| 59 | await this.emailInput.sendKeys(email); |
| 60 | await this.passwordInput.sendKeys(password); |
| 61 | await this.loginButton.click(); |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | // Usage |
| 66 | const loginPage = new LoginPage(); |
| 67 | await loginPage.login('user@test.com', 'password123'); |
| 68 | ``` |
| 69 | |
| 70 | ### protractor.conf.js |
| 71 | |
| 72 | ```javascript |
| 73 | exports.config = { |
| 74 | framework: 'jasmine', |
| 75 | seleniumAddress: 'http://localhost:4444/wd/hub', |
| 76 | specs: ['specs/**/*.spec.js'], |
| 77 | capabilities: { browserName: 'chrome' }, |
| 78 | jasmineNodeOpts: { defaultTimeoutInterval: 30000 }, |
| 79 | onPrepare: () => { |
| 80 | browser.waitForAngularEnabled(true); |
| 81 | } |
| 82 | }; |
| 83 | ``` |
| 84 | |
| 85 | ### Migration Guide |
| 86 | |
| 87 | | Protractor | Playwright | |
| 88 | |-----------|------------| |
| 89 | | `element(by.model('x'))` | `page.locator('[ng-model="x"]')` | |
| 90 | | `element(by.css('#id'))` | `page.locator('#id')` | |
| 91 | | `browser.get(url)` | `page.goto(url)` | |
| 92 | | `element.sendKeys(text)` | `locator.fill(text)` | |
| 93 | | `browser.sleep(ms)` | `page.waitForTimeout(ms)` | |
| 94 | | `browser.waitForAngular()` | Not needed (auto-wait) | |
| 95 | |
| 96 | |
| 97 | ### Cloud Execution on TestMu AI |
| 98 | |
| 99 | Set environment variables: `LT_USERNAME`, `LT_ACCESS_KEY` |
| 100 | |
| 101 | ```javascript |
| 102 | // conf.js |
| 103 | exports.config = { |
| 104 | seleniumAddress: `https://${process.env.LT_USERNAME}:${process.env.LT_ACCESS_KEY}@hub.lambdatest.com/wd/hub`, |
| 105 | capabilities: { |
| 106 | browserName: 'chrome', |
| 107 | 'LT:Options': { |
| 108 | user: process.env.LT_USERNAME, |
| 109 | accessKey: process.env.LT_ACCESS_KEY, |
| 110 | build: 'Protractor Build', |
| 111 | name: 'Protractor Test', |
| 112 | platformName: 'Windows 11', |
| 113 | video: true, |
| 114 | console: true, |
| 115 | network: true, |
| 116 | }, |
| 117 | }, |
| 118 | }; |
| 119 | ``` |
| 120 | ## Run: `npx protractor conf.js` (deprecated, use Playwright/Cypress instead) |
| 121 | |
| 122 | ## Deep Patterns |
| 123 | |
| 124 | For advanced patterns, debugging guides, CI/CD integration, and best practices, |
| 125 | see `reference/playbook.md`. |