Lesson 2 of 14

Lesson 02 — Arrays for QA automation

Title: Ordered Lists, Indexing, Length, and Safe Updates

Description: Arrays are used to store values in order, such as test data rows, API results, lines from a file, or related UI elements. This lesson shows how to access and update elements using indexes, how to add items with push, and why using delete for array items is usually not a good idea.

Why it matters for QA: In tests, you often compare lists (expect(actual).toEqual(expected)). Knowing how length works, how to get the last item, and how arrays behave helps you understand bugs like unexpected array size or missing values (undefined).


How to practice: Run snippets in the browser console or Node.


1. Creating arrays

An array is an ordered list. Elements can be any type.

javascriptjavascript
let empty = [];

let tags = ["smoke", "regression", "api"];
console.log(tags);

let mixed = [1, 2, "ok", "fail", null, true, false];
console.log(mixed);

2. Indexing (0-based)

First element is at index 0.

javascriptjavascript
let steps = ["open", "login", "assert"];
console.log(steps[0]); // "open"
console.log(steps[1]); // "login"
console.log(steps[2]); // "assert"

3. Length and last element

javascriptjavascript
let ids = ["u-100", "u-101", "u-102"];
console.log(ids.length); // 3

console.log(ids[ids.length - 1]); // "u-102"

4. Replacing and updating elements

Unlike strings, array slots are mutable—you assign a new value to a position.

javascriptjavascript
let statuses = ["pending", "pending", "done"];
statuses[0] = "failed";
console.log(statuses); // ["failed", "pending", "done"]

5. Updating string elements in the array

Each element is still a string: you replace the whole element, not one character inside it.

javascriptjavascript
let names = ["suite", "case", "step"];
names[0] = names[0] + "A";
names[1] = names[1] + "B";
names[2] = names[2] + "C";
console.log(names);

let labels = ["a", "b", "c"];
labels[0] += "!";
labels[1] += "!";
labels[2] += "!";
console.log(labels);

6. Increment and decrement on numeric elements

javascriptjavascript
let counts = [2, 3, 4, 5];
counts[0]++;
++counts[1];
counts[2]--;
--counts[3];
console.log(counts); // [3, 4, 3, 4]

7. Growing by index

You can assign past the current end; missing indices become empty slots (sparse array).

javascriptjavascript
let row = [];
row[0] = "id";
row[1] = "name";
row[2] = "role";
console.log(row);

Sparse gap (easy to create by mistake):

javascriptjavascript
let letters = ["x", "y", "z"];
letters[5] = "!";
console.log(letters);
// ["x", "y", "z", empty × 2, "!"] — indices 3 and 4 are holes
console.log(letters[3]); // undefined

8. push — add to the end

Preferred way to append.

javascriptjavascript
let queue = [];
queue.push("first");
queue.push("second");
queue.push("third");
console.log(queue);

9. Pitfall: using delete to remove an element by index

delete arr[i] removes the property at that index but does not shift the remaining elements. The array’s length stays the same, so you end up with a hole (an empty slot), not a shorter array.

javascriptjavascript
let items = ["alpha", "beta", "gamma"];
delete items[1];
console.log(items);     // [ 'alpha', <1 empty item>, 'gamma' ]
console.log(items.length); // still 3

Better patterns for QA code:

  • Remove by index and re-pack: items.splice(1, 1)
  • Or build a new array: items.filter(item => item !== "gamma")

10. Finding values: indexOf and lastIndexOf

When the same value appears more than once (for example duplicate "done" in a status log), indexOf returns the first index and lastIndexOf returns the last. Both return -1 if the value is not in the array.

javascriptjavascript
let statuses = ["done", "new", "running", "done"];
console.log(statuses.indexOf("done"));      // 0
console.log(statuses.lastIndexOf("done"));  // 3

QA note: Use these when you need the position of an item before splice, or to check that a string appears at least once (indexOf("error") !== -1).


11. Non-destructive ranges: slice

slice(start, end) returns a new array from start up to but not including end. The original array is unchanged—handy for taking a subset to assert on without mutating test data.

javascriptjavascript
let statuses = ["done", "new", "running", "done"];
console.log(statuses.slice(0, 2)); // ["done", "new"]
console.log(statuses.slice(1, 3)); // ["new", "running"]
console.log(statuses.slice(0, 1)); // ["done"]

QA note: slice(0, 1) has length 1 (only index 0). End index is exclusive, same rule as in many APIs.


Official docs


Quick recap

TopicTakeaway
arr[i]0-based; read and write slots
lengthNot always “count of defined values” if the array is sparse
pushAppend; keeps indices contiguous
deleteLeaves holes; usually wrong for “remove this list item”
indexOf / lastIndexOfFirst / last index of a value; -1 if missing
sliceNew sub-array; original unchanged; end index is exclusive

Suggested exercises

  1. Given let runs = [10, 20, 30];, log the sum of first and last element without hard-coding 30.
  2. Start with [] and push three test names; then replace the middle one with "skipped".
  3. Predict the output of let a = [1]; a[3] = 2; console.log(a.length, a[1]);.
  4. Rewrite the delete example using splice so the array becomes ["alpha", "gamma"] with length 2.

Homework

Short tasks (about 10–15 minutes). Click a task title to reveal the prompt.

Task 1: first plus last

Create an array of five numbers. Log the sum of the first and last elements without hard-coding the last index (use length).

Task 2: build a tiny suite list

Start with [], push three test case names, replace the middle one with "skipped", then log the whole array.

Task 3: sparse length

Run let a = ["x"]; a[3] = "y"; and log a.length and a[1]. In one sentence, explain why a[1] looks like that.

Task 4: pop vs shift

Create let tailDemo = ["a", "b", "c"], call pop() once, log tailDemo. Separately create let headDemo = ["a", "b", "c"], call shift() once, log headDemo. In one sentence, say which end each method removes from.

Task 5: increment a slot

Given let counts = [1, 2, 3], increment only index 1 using ++ on the element, then log counts.

Task 6: splice instead of delete

Turn ["alpha", "beta", "gamma"] into ["alpha", "gamma"] with splice (length must be 2). Log the result.

Task 7: empty check

Declare let queue = [] and log whether queue.length === 0 is true. Then push one item and log the same check again.

Task 8: clone before update

Create let queue = ["A", "B", "C"]. Remove the first item with shift(), add "D" with push(), then log the final array.

Task 9: position of an element

Create let statuses = ["new", "running", "done"]. Log the second element by index, then replace it with "skipped" and log the array.

Task 10: Removing the last element with .pop()

Create let values = [10, 20, 30, 40]. Remove the last element with pop(), then log the new length and the array itself.