testing-deployment-implementation
Write unit tests for components and services, implement E2E tests with Cypress, set up test mocks, optimize production builds, configure CI/CD pipelines, and deploy to production platforms.
What this skill does
# Testing & Deployment Implementation Skill
## Unit Testing Basics
### TestBed Setup
```typescript
import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
describe('UserService', () => {
let service: UserService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [UserService]
});
service = TestBed.inject(UserService);
httpMock = TestBed.inject(HttpTestingController);
});
afterEach(() => {
httpMock.verify();
});
});
```
### Component Testing
```typescript
describe('UserListComponent', () => {
let component: UserListComponent;
let fixture: ComponentFixture<UserListComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [UserListComponent],
imports: [CommonModule, HttpClientTestingModule],
providers: [UserService]
}).compileComponents();
fixture = TestBed.createComponent(UserListComponent);
component = fixture.componentInstance;
});
it('should display users', () => {
const mockUsers: User[] = [
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' }
];
component.users = mockUsers;
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
const userElements = compiled.querySelectorAll('.user-item');
expect(userElements.length).toBe(2);
});
it('should call service on init', () => {
const userService = TestBed.inject(UserService);
spyOn(userService, 'getUsers').and.returnValue(of([]));
component.ngOnInit();
expect(userService.getUsers).toHaveBeenCalled();
});
});
```
### Testing Async Operations
```typescript
// Using fakeAsync and tick
it('should load users after delay', fakeAsync(() => {
const userService = TestBed.inject(UserService);
spyOn(userService, 'getUsers').and.returnValue(
of([{ id: 1, name: 'John' }]).pipe(delay(1000))
);
component.ngOnInit();
expect(component.users.length).toBe(0);
tick(1000);
expect(component.users.length).toBe(1);
}));
// Using waitForAsync
it('should handle async operations', waitForAsync(() => {
const userService = TestBed.inject(UserService);
spyOn(userService, 'getUsers').and.returnValue(
of([{ id: 1, name: 'John' }])
);
component.ngOnInit();
fixture.whenStable().then(() => {
expect(component.users.length).toBe(1);
});
}));
```
## Mocking Services
### HTTP Mocking
```typescript
it('should fetch users from API', () => {
const mockUsers: User[] = [{ id: 1, name: 'John' }];
service.getUsers().subscribe(users => {
expect(users.length).toBe(1);
expect(users[0].name).toBe('John');
});
const req = httpMock.expectOne('/api/users');
expect(req.request.method).toBe('GET');
req.flush(mockUsers);
});
// POST with error handling
it('should handle errors', () => {
service.createUser({ name: 'Jane' }).subscribe(
() => fail('should not succeed'),
(error) => expect(error.status).toBe(400)
);
const req = httpMock.expectOne('/api/users');
req.flush('Invalid user', { status: 400, statusText: 'Bad Request' });
});
```
### Service Mocking
```typescript
class MockUserService {
getUsers() {
return of([
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' }
]);
}
}
@Component({
selector: 'app-test',
template: '<div>{{ (users$ | async)?.length }}</div>'
})
class TestComponent {
users$ = this.userService.getUsers();
constructor(private userService: UserService) {}
}
describe('TestComponent with Mock', () => {
let component: TestComponent;
let fixture: ComponentFixture<TestComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [TestComponent],
providers: [
{ provide: UserService, useClass: MockUserService }
]
}).compileComponents();
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should render users', () => {
const div = fixture.nativeElement.querySelector('div');
expect(div.textContent).toContain('2');
});
});
```
## E2E Testing with Cypress
### Basic E2E Test
```typescript
describe('User List Page', () => {
beforeEach(() => {
cy.visit('/users');
});
it('should display user list', () => {
cy.get('[data-testid="user-item"]')
.should('have.length', 10);
});
it('should filter users by name', () => {
cy.get('[data-testid="search-input"]')
.type('John');
cy.get('[data-testid="user-item"]')
.should('have.length', 1)
.should('contain', 'John');
});
it('should navigate to user detail', () => {
cy.get('[data-testid="user-item"]').first().click();
cy.location('pathname').should('include', '/users/');
cy.get('[data-testid="user-detail"]').should('be.visible');
});
});
```
### Page Object Model
```typescript
// user.po.ts
export class UserPage {
navigateTo(path: string = '/users') {
cy.visit(path);
return this;
}
getUsers() {
return cy.get('[data-testid="user-item"]');
}
getUserByName(name: string) {
return cy.get('[data-testid="user-item"]').contains(name);
}
clickUser(index: number) {
this.getUsers().eq(index).click();
return this;
}
searchUser(query: string) {
cy.get('[data-testid="search-input"]').type(query);
return this;
}
}
// Test using PO
describe('User Page', () => {
const page = new UserPage();
beforeEach(() => {
page.navigateTo();
});
it('should find user by name', () => {
page.searchUser('John');
page.getUsers().should('have.length', 1);
});
});
```
## Build Optimization
### AOT Compilation
```typescript
// angular.json
{
"projects": {
"app": {
"architect": {
"build": {
"options": {
"aot": true,
"outputHashing": "all",
"sourceMap": false,
"optimization": true,
"buildOptimizer": true,
"namedChunks": false
}
}
}
}
}
}
```
### Bundle Analysis
```bash
# Install webpack-bundle-analyzer
npm install --save-dev webpack-bundle-analyzer
# Run analysis
ng build --stats-json
webpack-bundle-analyzer dist/app/stats.json
```
### Code Splitting
```typescript
// app-routing.module.ts
const routes: Routes = [
{ path: '', component: HomeComponent },
{
path: 'admin',
loadChildren: () =>
import('./admin/admin.module').then(m => m.AdminModule)
},
{
path: 'users',
loadChildren: () =>
import('./users/users.module').then(m => m.UsersModule)
}
];
```
## Deployment
### Production Build
```bash
# Build for production
ng build --configuration production
# Output directory
dist/app/
# Serve locally
npx http-server dist/app/
```
### Deployment Targets
**Firebase:**
```bash
npm install -g firebase-tools
firebase login
firebase init hosting
firebase deploy
```
**Netlify:**
```bash
npm run build
# Drag and drop dist/ folder to Netlify
# Or use CLI:
npm install -g netlify-cli
netlify deploy --prod --dir=dist/app
```
**GitHub Pages:**
```bash
ng build --output-path docs --base-href /repo-name/
git add docs/
git commit -m "Deploy to GitHub Pages"
git push
# Enable in repository settings
```
**Docker:**
```dockerfile
# Build stage
FROM node:18 as build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Serve stage
FROM nginx:alpine
COPY --from=build /app/dist/app /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
```
## CI/CD Pipelines
### GitHub Actions
```yaml
name: CI/CD
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-nodeRelated in Cloud & DevOps
appbuilder-action-scaffolder
IncludedCreate, implement, deploy, and debug Adobe Runtime actions with consistent layout, validation, and error handling. Use this skill whenever the user needs to add actions to an App Builder project, understand action structure (params, response format, web/raw actions), configure actions in the manifest, use App Builder SDKs (State, Files, Events, database), deploy and invoke actions via CLI, debug action issues, or implement patterns such as webhook receivers, custom event providers, journaling consumers, large payload redirects, action sequence pipelines, and Asset Compute workers. Also trigger when users mention serverless functions in Adobe context, action logging, IMS authentication for actions, or cron-style scheduled actions.
orchestrating-datacloud
IncludedSalesforce Data Cloud product orchestrator for connect→prepare→harmonize→segment→act workflows. Use this skill when the user needs a multi-step Data Cloud pipeline, cross-phase troubleshooting, or data space and data kit management. TRIGGER when: user needs a multi-step Data Cloud pipeline, asks to set up or troubleshoot Data Cloud across phases, manages data spaces or data kits, or wants a cross-phase sf data360 workflow. DO NOT TRIGGER when: work is isolated to a single phase (use the matching phase-specific skill), the task is STDM/session tracing/parquet telemetry (use observing-agentforce), standard CRM SOQL (use querying-soql), or Apex implementation (use generating-apex).
github-project-automation
IncludedAutomate GitHub repository setup with CI/CD workflows, issue templates, Dependabot, and CodeQL security scanning. Includes 12 production-tested workflows and prevents 18 errors: YAML syntax, action pinning, and configuration. Use when: setting up GitHub Actions CI/CD, creating issue/PR templates, enabling Dependabot or CodeQL scanning, deploying to Cloudflare Workers, implementing matrix testing, or troubleshooting YAML indentation, action version pinning, secrets syntax, runner versions, or CodeQL configuration. Keywords: github actions, github workflow, ci/cd, issue templates, pull request templates, dependabot, codeql, security scanning, yaml syntax, github automation, repository setup, workflow templates, github actions matrix, secrets management, branch protection, codeowners, github projects, continuous integration, continuous deployment, workflow syntax error, action version pinning, runner version, github context, yaml indentation error
sf-datacloud
IncludedSalesforce Data Cloud product orchestrator for connect→prepare→harmonize→segment→act workflows. TRIGGER when: user needs a multi-step Data Cloud pipeline, asks to set up or troubleshoot Data Cloud across phases, manages data spaces or data kits, or wants a cross-phase `sf data360` workflow. DO NOT TRIGGER when: work is isolated to a single phase (use the matching sf-datacloud-* skill), the task is STDM/session tracing/parquet telemetry (use sf-ai-agentforce-observability), standard CRM SOQL (use sf-soql), or Apex implementation (use sf-apex).
fabric-cli
IncludedUse this skill for Fabric.so CLI workflows with the `fabric` terminal command: diagnose/install/login, search or browse a Fabric library, save notes/links/files, create folders, ask the Fabric AI assistant, manage tasks/workspaces, generate shell completion, check subscription usage, produce JSON output, and use Fabric as persistent agent memory. Do not use for Microsoft Fabric/Azure/Power BI `fab`, Daniel Miessler's Fabric framework, Python Fabric SSH, Fabric.js, or textile/fashion fabric.
lark
IncludedLark/Feishu CLI skills: lark-cli operations for docs, markdown, sheets, base, calendar, im, mail, task, okr, drive, wiki, slides, whiteboard, apps, approval, attendance, contact, vc, minutes, event. Use when the user needs to operate Lark/Feishu resources via lark-cli, send messages, manage documents, spreadsheets, calendars, tasks, OKRs, deploy web pages, or any Feishu/Lark workspace operations.