The Front-End Fresh Workshop


Agenda
Sept 25th
Front-End Engineering in 2024 & Mastering React

Oct 2nd
Building Large Scale Web Apps
Oct 9th
Debugging + Testing + Interviewing
Oct 16th
Leveling Up From Junior To Senior To Staff

Today's Agenda
Building Large Scale Web Apps

- Testing
- Personal Branding
- Interviewing
- Debugging

Introductions!
Ayman
Fernando
today's folks
Mohamud
M A
Zubair
Ahmed







Q/A!
Any questions before we get started?

Debugging
My regular debugging steps when errors occur — check network request logs / JavaScript Console / React DevTools

Debugging


Debugging


Debugging


Debugging


Debugging


Debugging


Debugging


Debugging


Testing
Testing is the process of evaluating a system or
its components to determine whether they meet the specified
requirements.
Local
CI

Testing
Unit Tests
Integration Tests
E2E Tests

Testing
Unit Tests
focus on examining individual components or functions within an application, isolated from the rest of the codebase

Testing
import React, { useState } from "react";
const Counter = () => {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
const decrement = () => {
setCount(count - 1);
};
return (
<div>
<button onClick={decrement}>-</button>
<span>{count}</span>
<button onClick={increment}>+</button>
</div>
);
};
Testing
import React from "react";
describe("Counter component", () => {
it("initial count is 0", () => {
// ...
});
it('increases count on "+" button click', () => {
// ...
});
it('decreases count on "-" button click', () => {
// ...
});
});

Testing


Testing
import React from "react";
import { render } from "@testing-library/react";
import Counter from "./Counter";
describe("Counter component", () => {
it("renders with initial count of 0", () => {
const { getByText } = render(<Counter />);
expect(getByText("0")).not.toBeNull();
});
// ...
});
Testing
import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import Counter from './Counter'
describe('Counter component', () => {
it('renders with initial count of 0', () => {
const { getByText } = render(<Counter />);
expect(getByText('0')).not.toBeNull();
});
it('increases count on "+" button click', () => {
const { getByText } = render(<Counter />);
const incrementButton = getByText('+');
fireEvent.click(incrementButton);
expect(getByText('1')).not.toBeNull();
});
it('decreases count on "-" button click', () => {
const { getByText } = render(<Counter />);
const decrementButton = getByText('-');
fireEvent.click(decrementButton);
expect(getByText('-1')).not.toBeNull();
});
});
Testing
Arrange, Act, Assert

Testing
import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import Counter from './Counter'
describe('Counter component', () => {
// ...
it('increases count on "+" button click', () => {
const { getByText } = render(<Counter />);
const incrementButton = getByText('+');
fireEvent.click(incrementButton);
expect(getByText('1')).not.toBeNull();
});
it('decreases count on "-" button click', () => {
// ...
});
});Arrange
Act
Assert

Testing
End-to-end Tests
Evaluate the complete functionality of an application by simulating real-world user interactions across multiple components and services


Testing
import React from "react";
import {
BrowserRouter as Router,
Route,
Switch,
} from "react-router-dom";
import HomePage from "./HomePage";
import CounterList from "./CounterList";
function App() {
return (
<Router>
<Switch>
<Route
exact
path="/"
component={HomePage}
/>
<Route
path="/counter"
component={CounterList}
/>
</Switch>
</Router>
);
}
export default App;import React, {
useState,
useEffect,
} from "react";
import Counter from "./Counter";
const CounterList = () => {
const [items, setItems] = useState([]);
useEffect(() => {
fetch("/api/items")
.then((response) => response.json())
.then((data) => setItems(data));
}, []);
return (
<div>
<h1>Counter List</h1>
{items.map((item) => (
<Counter key={item.id} item={item} />
))}
</div>
);
};
export default CounterList;
Testing
import React, { useState } from "react";
const Counter = ({ item }) => {
const [count, setCount] = useState(item.count);
const updateCount = (change) => {
fetch(`/api/items/${item.id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
count: count + change,
}),
})
.then((response) => response.json())
.then((updatedItem) => {
setCount(updatedItem.count);
});
};
return (
<div>
<h3>{item.name}</h3>
<div>
Count:{" "}
<span className="count">{count}</span>
</div>
<button
className="increment"
onClick={() => updateCount(1)}
>
+
</button>
<button
className="decrement"
onClick={() => updateCount(-1)}
>
-
</button>
</div>
);
};
Testing
We can write tests for the “/counter” route that simulate user interactions such as fetching data, incrementing/decrementing count values, persisting changes to the server, and syncing updates with clients.
Should we make actual API requests in our tests or stub/mock them?
Use real API requests sparingly and only when testing critical paths of an application (e.g., login, sign up, billing, etc.). Otherwise, stubbing API responses should be used for the vast majority of tests.

Testing
describe('/counter', () => {
beforeEach(() => {
cy.visit('/counter');
});
// ...
});
Testing
describe('/counter', () => {
beforeEach(() => {
cy.intercept('GET', '/api/items', [
{ id: 1, name: 'Item 1', count: 0 },
{ id: 2, name: 'Item 2', count: 0 },
]);
cy.visit('/counter');
});
// ...
});
Testing
describe('/counter', () => {
beforeEach(() => {
cy.intercept('GET', '/api/items', [
{ id: 1, name: 'Item 1', count: 0 },
{ id: 2, name: 'Item 2', count: 0 },
]);
cy.visit('/counter');
});
it('displays counters fetched from API', () => {
cy.get('.count').should(($counts) => {
expect($counts).to.have.length(2);
expect($counts.eq(0)).to.contain.text('0');
expect($counts.eq(1)).to.contain.text('0');
});
});
// ...
});
Testing
describe("/counter", () => {
beforeEach(() => {
cy.intercept('GET', '/api/items', [
{ id: 1, name: 'Item 1', count: 0 },
{ id: 2, name: 'Item 2', count: 0 },
]);
cy.visit("/counter");
});
it("displays counters fetched from API", () => {
// ...
});
it("increases count on increment click", () => {
const updatedItem = {
id: 1,
name: "Item 1",
count: 2,
};
cy.get(".increment").first().click().click();
cy.get(".count")
.first()
.should("contain.text", updatedItem.count);
});
// ...
});
Testing
Integration Tests
Generally focus on testing the interaction between multiple units or components in an application. Fill the gap between Unit tests and E2E tests.

Testing
import React from "react";
import { render, fireEvent, waitFor } from "@testing-library/react";
import { Counter } from "./Counter";
// Mock API service
jest.mock("./apiService", () => ({
updateCount: jest.fn(),
}));
describe("Counter", () => {
test("UI updates on item count++", async () => {
const mockData = { id: 1, name: "Item 1", count: 2 };
const { queryByText } = render(
<Counter
item={{
id: 1,
name: "Item 1",
count: 0,
}}
/>,
);
// Click increment button
fireEvent.click(queryByText("+"));
// Wait for API response
await waitFor(() =>
expect(
require("./apiService").updateCount,
).toHaveBeenCalledWith(1, mockData.count),
);
// Check for UI update with new data
expect(
queryByText("Count: 2"),
).not.toBeNull();
});
});
Testing
What tools we use in our tests doesn’t dictate the type of tests we’re writing. However, not mocking API requests in our tests, leveraging actual test environments, and seeding data in our back-end specific for testing are all features that resemble more of an actual end-to-end testing environment.
On the flip side, testing the interaction between components, mocking API requests, and focusing on specific parts of the application flow are characteristics more commonly associated with integration testing.

Testing
What kind of tests should we be focusing on?

Testing

Testing Pyramid first coined by Mike Cohn.

Testing
Testing Trophy first coined by Kent C Dodds.


Testing
Snapshot Tests
A type of testing methodology that focuses on capturing the UI output of a component at a specific point in time and then comparing it with future outputs to ensure that no unintended changes have occurred

Testing
export default function Link({
page,
children,
}) {
return <a href={page}>{children}</a>
}
Testing
import renderer from "react-test-renderer";
import Link from "../Link";
it("renders correctly", () => {
const tree = renderer
.create(
<Link page="http://www.facebook.com">
Facebook
</Link>,
)
.toJSON();
expect(tree).toMatchSnapshot();
});exports[`renders correctly 1`] = `
<a
href="http://www.facebook.com"
>
Facebook
</a>
`;
Testing
import renderer from 'react-test-renderer';
import Link from '../Link';
it('renders correctly', () => {
const tree = renderer
.create(
<Link page="http://www.instagram.com">
Instagram
</Link>
)
.toJSON();
expect(tree).toMatchSnapshot();
});
Testing
FAIL src/Link.test.js
● renders correctly
expect(value).toMatchSnapshot()
Received value does not match stored snapshot ...
- Expected
+ Received
<a
- href="http://www.facebook.com"
+ href="http://www.instagram.com"
>
- Facebook
+ Instagram
</a>
7 |
8 | it("renders correctly", () => {jest --updateSnapshot
Testing
exports[`renders correctly 1`] = `
<a
href="http://www.instagram.com"
>
Instagram
</a>
`;
Testing


Testing
Snapshot tests are important only if the rendered output of a component is critical to the functionality or design of the application and must remain consistent over time.
Example I've seen — Internal Component Libraries

Testing
Q/A!

Interviewing
This week we'll talk about some tips around interviewing. Next week, we'll discuss tips around getting an interview (amongst other things).
Front-End Engineering

Interviewing
Note: I am speaking from the perspective of North America however a lot of the things I share here can be transferable to wherever you might be based in.

Interviewing
The Google's/Meta's/SF San Fran Companies
The Fortune500 (i.e., bigger name companies)
Smaller to medium sized companies

Interviewing
The Google's/Meta's/Netflix's/etc.
The Fortune500 (i.e., bigger name companies)
Smaller to medium sized companies
Phone Screen
Behavioural Interview
Technical Screens
This can differ the most depending on company + role

Interviewing
The Google's/Meta's/Netflix's/etc.
Data Structures & Algorithms

Interviewing
The Google's/Meta's/Netflix's/etc.
Data Structures
Organize and store data efficiently
Arrays, Linked Lists, Stacks, Queues
Trees (Binary, AVL), Graphs, Hash Tables
Algorithms
Step-by-step procedures to solve problems
Sorting: Quick Sort, Merge Sort, Bubble Sort
Searching: Binary Search, Depth-First Search (DFS), Breadth-First Search (BFS)
Big (O)

Interviewing
The Google's/Meta's/Netflix's/etc.
[Question: Reverse an Array]
Write a function in JavaScript that takes an array as input and
returns the array in reverse order without using the built-in
reverse() method.
Input: [1, 2, 3, 4, 5]
Output: [5, 4, 3, 2, 1]
---
function reverseArray(arr) {
let reversedArr = [];
for (let i = arr.length - 1; i >= 0; i--) {
reversedArr.push(arr[i]);
}
return reversedArr;
}
// Test the function
// Output: [5, 4, 3, 2, 1]
console.log(reverseArray([1, 2, 3, 4, 5]));
Interviewing
The Google's/Meta's/Netflix's/etc.
[Question: Detect a Cycle in a Linked List]
Write a function in JavaScript to determine if a
given singly linked list contains a cycle.
A cycle occurs when a node’s next pointer points
to a previous node in the list, forming a loop.
Input: 1 -> 2 -> 3 -> 4 -> 5 -> 2 (cycle back to node 2)
Output: true
Input: 1 -> 2 -> 3 -> 4 -> 5 -> null
Output: false
---
function hasCycle(head) {
if (!head || !head.next) return false;
let slow = head;
let fast = head;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
if (slow === fast) {
return true;
}
}
return false;
}

Interviewing
The Google's/Meta's/Netflix's/etc.



Interviewing
The Fortune500 (i.e., bigger name companies)
Smaller to medium sized companies
More likely to ask a front-end development related question.

Interviewing
The Fortune500 (i.e., bigger name companies)
Smaller to medium sized companies
How would you go about designing and building the UI of a shopping cart?
Build an image carousel component in React

Interviewing
The Fortune500 (i.e., bigger name companies)
Smaller to medium sized companies
React
UI/CSS
API
TypeScript? Good Markup? Etc.

Interviewing
Behavioural Interviews
System Design (Front-End)

Interviewing
Behavioural Interviews
Think of projects you've worked on
S.T.A.R Method
Situation, Task, Action, and Result

Interviewing
Behavioural Interviews
App Store (Shopify)
S.T.A.R Method
Situation, Task, Action, and Result
Instacart (Ads Team)
Doordash (Experimentation)
- Built a Results tabe
- Built a Metrics Explorer product
- Mentored 4 new hires
- etc.

Interviewing
Behavioural Interviews
Tell me about a time when you worked on a team project and faced a challenge.

Interviewing
System Design
How would you design & build Facebook's News Feed

Interviewing
System Design
Component Architecture
Data API
Infinite Scroll/Pagination
Optimization (Performance)
Host images/assets on an image service
Accessibility/TypeScript/etc./etc.

Interviewing
When you've gotten an interview
Gather information from recruiter/hiring manager
Search around on Glassdoor
Give yourself some time to prepare
When you hear back — keep the recruiter/hiring manager in your contacts
just to get an idea on how the interview is

Front-End Fresh (Session #3)
- Building a Personal Brand & Applying to Roles
What's coming next week?

Front-End Fresh (Session #3)
Q/A
The Front-End Fresh Workshop (Oct 9th)
By djirdehh
The Front-End Fresh Workshop (Oct 9th)
- 119