Test data is rarely a single value. You have a list of browsers to test against, a list of accepted status codes, a list of test users with different roles. The structure that holds those lists in JavaScript is the array — an ordered collection of values you can index into, walk through, add to, and shrink. This lesson covers the syntax, the operations, and the 0-based-index detail that catches every beginner once.
Creating an array
The most common way to make an array is the literal syntax — square brackets with comma-separated values:
const browsers = ["Chrome", "Firefox", "Safari", "Edge"];
console.log(browsers);Output:
[ 'Chrome', 'Firefox', 'Safari', 'Edge' ]
Empty arrays are useful when you'll add items later:
const failures = [];
console.log(failures.length); // 0Arrays can technically hold mixed types — [200, "OK", true] is legal — but in test code you almost always want one consistent type per array. Mixed-type arrays make it harder to use the array methods you'll meet in the next lesson.
Indexing — and the 0-based gotcha
You access items by their index — a number in square brackets. JavaScript counts from 0, not 1:
const browsers = ["Chrome", "Firefox", "Safari", "Edge"];
console.log(browsers[0]); // Chrome ← first item
console.log(browsers[1]); // Firefox
console.log(browsers[2]); // Safari
console.log(browsers[3]); // Edge ← last item
console.log(browsers[4]); // undefined ← past the endThe array has 4 items, but their indices run from 0 to 3. The first item is index 0, the last item is index length-1. Forgetting that off-by-one is the source of a vast number of beginner bugs — and a few experienced ones too.
Negative indices don't work in JavaScript the way they do in some other languages — browsers[-1] returns undefined, not the last item. To get the last item, use browsers[browsers.length - 1] or the modern browsers.at(-1).
Length
.length is the number of items in the array — not the highest index, but the count.
const browsers = ["Chrome", "Firefox", "Safari"];
console.log(browsers.length); // 3length is also writable. Setting arr.length = 0 empties the array; setting it shorter than the current length truncates. You'll rarely need this in test code, but it's a useful trick to know about.
Adding and removing items
Four built-in methods cover the four corners — adding/removing at the start/end of the array:
const queue = ["login", "checkout"];
queue.push("logout"); // add to end: ["login", "checkout", "logout"]
queue.unshift("setup"); // add to start: ["setup", "login", "checkout", "logout"]
const last = queue.pop(); // remove end: "logout" — array now ["setup", "login", "checkout"]
const first = queue.shift(); // remove start: "setup" — array now ["login", "checkout"]
console.log(queue);Output:
[ 'login', 'checkout' ]
For a more surgical insert/remove, splice operates at a specific index:
const tests = ["login", "checkout", "logout"];
tests.splice(1, 1); // at index 1, remove 1 item
console.log(tests); // ["login", "logout"]
tests.splice(1, 0, "search"); // at index 1, remove 0 items, insert "search"
console.log(tests); // ["login", "search", "logout"]splice mutates the array in place. If you need a non-mutating version, use the spread operator (covered two lessons from now).
Searching — includes and indexOf
To check whether something is in an array, includes returns a boolean:
const acceptedStatuses = [200, 201, 204];
console.log(acceptedStatuses.includes(200)); // true
console.log(acceptedStatuses.includes(404)); // falseTo find where an item is, indexOf returns the index — or -1 if it isn't there:
const browsers = ["Chrome", "Firefox", "Safari"];
console.log(browsers.indexOf("Firefox")); // 1
console.log(browsers.indexOf("Opera")); // -1includes was added later for exactly this readability win — arr.indexOf(x) !== -1 is uglier than arr.includes(x). Use includes when you only need a yes/no answer.
Both use strict equality (===) under the hood, so the type-coercion warnings from chapter 2 still apply: [200].includes("200") is false.
A real test fixture as an array
The shape of test data you'll actually see — an array of objects, each representing one test case.
const testCases = [
{ name: "login", suite: "auth", priority: "P1" },
{ name: "checkout", suite: "commerce", priority: "P0" },
{ name: "search", suite: "discovery", priority: "P2" },
{ name: "logout", suite: "auth", priority: "P2" }
];
console.log(testCases.length); // 4
console.log(testCases[0].name); // "login" — array index, then object key
console.log(testCases[1].priority); // "P0"Two layers — array indexing (testCases[1]) gets you the object, then object access (.priority) gets you the field. This nested shape is where 90% of test data lives.
A look at the structure
testCases array — index, name, priority
(The bars encode priority — a higher number means lower priority. The labels carry the array index, the test name, and the priority — all the bits that matter when reading a test fixture at a glance.)
⚠️ Common mistakes
- Using index 1 to mean "the first item." Index 1 is the second item. The first item lives at index 0. The same off-by-one bites in
forloop bounds:i <= arr.lengthreads one past the end. - Mixing types in a single array.
[200, "OK", true]is legal but confuses every array method that follows. Keep arrays homogeneous in test code — an array of status codes, an array of user objects, an array of test names. - Forgetting that
splicemutates.arr.splice(0, 1)modifiesarrin place. If something else has a reference to the same array, that reference now sees the change. Be deliberate when you mutate; consider[...arr].splice(...)or the moderntoSplicedto avoid it.
🎯 Practice task
Build a small list of test users. 15-20 minutes.
- In your
js-for-qafolder, createusers.js. - Declare a
const users = [](empty array). - Use
pushto add 4 user objects, each with{ name, role }. Mix the roles: at least one admin, two members, one guest. - Print
users.lengthand each user with their index —console.log(0, users[0]), etc. - Build an array of just the names:
const names = users.map(u => u.name);. Usenames.includes("Alice")to check whether Alice is in the list. (includesdoes strict equality, so it works on primitive strings but not on object literals.) - Use
spliceto remove the second user. Print the array again. - Stretch: print the last user using
users.length - 1and again usingusers.at(-1). Confirm both give the same result. Then tryusers[-1]— confirm it returnsundefined(not the last item).
The next lesson introduces the array methods that replace most for-loops in test code: forEach, map, filter, and find.