JavaScript Variables Practice Programs with Solutions (32 Programs)

Practise JavaScript variables with 32 programs, each with a full solution, the exact output and a short explanation. The programs start with the basics, move to intermediate problems and finish with real-world scenarios from test automation, such as test data, prices, form inputs and test results. They are written for testers learning JavaScript for Playwright.

Advertisement

How to practise: read the task, write your own solution first, then open Show solution to compare. Run any program with node program.js.

New to this topic? Read the JavaScript Variables lesson first.

JavaScript Beginner Programs

1. Declare and print variablesBeginner

Declare a variable testerName with your name and a variable experienceYears with a number, then print both.

Show solution
let testerName = 'Asha';
let experienceYears = 3;
console.log('Tester:', testerName);
console.log('Experience (years):', experienceYears);

Output

Tester: Asha
Experience (years): 3

Explanation: let declares a variable that holds a value. console.log prints its arguments separated by a space.

2. Reassign a let variableBeginner

Create browser with the value 'chromium', print it, change it to 'firefox' and print it again.

Show solution
let browser = 'chromium';
console.log('Before:', browser);
browser = 'firefox';
console.log('After:', browser);

Output

Before: chromium
After: firefox

Explanation: variables declared with let can be reassigned. The second assignment replaces the old value.

3. Constants cannot be reassignedBeginner

Store a base URL in a const, then try to reassign it inside try/catch and print the error message.

Show solution
const BASE_URL = 'https://qa.example.com';
try {
  BASE_URL = 'https://prod.example.com';
} catch (error) {
  console.log('Error:', error.message);
}
console.log('BASE_URL is still', BASE_URL);

Output

Error: Assignment to constant variable.
BASE_URL is still https://qa.example.com

Explanation: a const binding cannot be reassigned, so the assignment throws a TypeError. The original value stays unchanged.

4. Swap two variables with a temporary variableBeginner

Swap the values of a = 10 and b = 20 using a third variable and print them before and after.

Show solution
let a = 10;
let b = 20;
console.log('Before swap: a =', a, 'b =', b);
let temp = a;
a = b;
b = temp;
console.log('After swap: a =', a, 'b =', b);

Output

Before swap: a = 10 b = 20
After swap: a = 20 b = 10

Explanation: the temporary variable keeps the first value safe while it is overwritten.

5. Swap two variables with destructuringBeginner

Swap first = 'login' and second = 'logout' without a temporary variable.

Show solution
let first = 'login';
let second = 'logout';
[first, second] = [second, first];
console.log(first, second);

Output

logout login

Explanation: array destructuring builds a temporary array [second, first] and unpacks it back into the two variables in one step.

6. Declare several variables in one statementBeginner

Declare passed, failed and skipped test counts in a single let statement and print the total.

Show solution
let passed = 42, failed = 3, skipped = 5;
let total = passed + failed + skipped;
console.log('Total tests:', total);

Output

Total tests: 50

Explanation: one let can declare several comma-separated variables. Readability usually favours one per line in real projects.

7. Uninitialised variableBeginner

Declare result without a value and print it and its type.

Show solution
let result;
console.log(result);
console.log(typeof result);

Output

undefined
undefined

Explanation: a declared but unassigned variable holds undefined, whose type is also 'undefined'.

8. Build a message with a template literalBeginner

Use variables user = 'qa_admin' and role = 'Admin' to print Logged in as qa_admin (Admin).

Show solution
const user = 'qa_admin';
const role = 'Admin';
const message = `Logged in as ${user} (${role})`;
console.log(message);

Output

Logged in as qa_admin (Admin)

Explanation: template literals (backticks) insert variable values with ${...}.

9. Increment a counterBeginner

Start retryCount at 0, increase it three times using different syntax and print it after each step.

Show solution
let retryCount = 0;
retryCount = retryCount + 1;
console.log(retryCount);
retryCount += 1;
console.log(retryCount);
retryCount++;
console.log(retryCount);

Output

1
2
3

Explanation: x = x + 1, x += 1 and x++ all add one to a let variable.

10. Valid variable namesBeginner

Create variables named with camelCase, a leading underscore and a dollar sign, then print them together.

Show solution
const firstName = 'Ravi';
const _internalId = 101;
const $price = 499;
console.log(firstName, _internalId, $price);

Output

Ravi 101 499

Explanation: names may start with a letter, _ or $, and must not start with a digit. camelCase is the usual convention.

JavaScript Intermediate Programs

11. Block scope with letIntermediate

Declare status outside an if block and a different status inside it. Print both to show they are separate.

Show solution
let status = 'outer';
if (true) {
  let status = 'inner';
  console.log('Inside block:', status);
}
console.log('Outside block:', status);

Output

Inside block: inner
Outside block: outer

Explanation: let is block-scoped, so the inner status exists only inside the braces and does not affect the outer one.

12. var ignores block scopeIntermediate

Repeat the previous program using var and observe the difference.

Show solution
var status = 'outer';
if (true) {
  var status = 'inner';
  console.log('Inside block:', status);
}
console.log('Outside block:', status);

Output

Inside block: inner
Outside block: inner

Explanation: var is function-scoped, so both declarations refer to the same variable and the block overwrites it.

13. Hoisting with varIntermediate

Print a var variable before the line that declares it.

Show solution
console.log('Before declaration:', environment);
var environment = 'staging';
console.log('After declaration:', environment);

Output

Before declaration: undefined
After declaration: staging

Explanation: var declarations are hoisted and initialised with undefined, so the first log prints undefined instead of throwing.

14. Temporal dead zone with letIntermediate

Access a let variable before its declaration inside try/catch and print the error name.

Show solution
try {
  console.log(timeout);
  let timeout = 30000;
} catch (error) {
  console.log(error.name + ': ' + error.message);
}

Output

ReferenceError: Cannot access 'timeout' before initialization

Explanation: let and const are hoisted but not initialised. Using them before the declaration throws a ReferenceError (the temporal dead zone).

15. const object can still changeIntermediate

Store test settings in a const object, change one property and print the object.

Show solution
const settings = { headless: true, retries: 0 };
settings.retries = 2;
console.log(settings);

Output

{ headless: true, retries: 2 }

Explanation: const stops reassignment of the variable, not changes to the object it points to.

16. Freeze a configuration objectIntermediate

Freeze a config object, try to change it and print it to show the change was ignored.

Show solution
const config = Object.freeze({ browser: 'chromium', workers: 4 });
config.workers = 8;
console.log(config.workers);
console.log(Object.isFrozen(config));

Output

4
true

Explanation: Object.freeze makes properties read-only. In non-strict code the assignment is silently ignored.

17. Loop variable scope: let vs varIntermediate

Collect functions in a loop using let and using var, then call them to see which values they remember.

Show solution
const withLet = [];
for (let i = 0; i < 3; i++) withLet.push(() => i);
const withVar = [];
for (var j = 0; j < 3; j++) withVar.push(() => j);
console.log('let:', withLet.map(f => f()));
console.log('var:', withVar.map(f => f()));

Output

let: [ 0, 1, 2 ]
var: [ 3, 3, 3 ]

Explanation: let creates a new binding for each loop iteration. var shares one variable, so every function sees its final value 3.

18. Shadowing in nested blocksIntermediate

Use the same name level in three nested scopes and print it from each one.

Show solution
const level = 'file';
{
  const level = 'block';
  {
    const level = 'nested block';
    console.log(level);
  }
  console.log(level);
}
console.log(level);

Output

nested block
block
file

Explanation: an inner declaration shadows outer ones with the same name. Each scope sees its nearest declaration.

19. Variables copy primitives by valueIntermediate

Copy a number into another variable, change the copy and print both.

Show solution
let originalTimeout = 5000;
let copiedTimeout = originalTimeout;
copiedTimeout = 10000;
console.log('original:', originalTimeout);
console.log('copy:', copiedTimeout);

Output

original: 5000
copy: 10000

Explanation: primitives such as numbers are copied by value, so changing the copy does not affect the original.

20. Variables share objects by referenceIntermediate

Assign an object to a second variable, change it through the second variable and print the first.

Show solution
const user = { name: 'Asha', active: true };
const sameUser = user;
sameUser.active = false;
console.log(user.active);
console.log(user === sameUser);

Output

false
true

Explanation: both variables point to the same object, so a change through either one is visible through both.

JavaScript Real-World QA Scenario Programs

21. Store environment URLsReal-world

Store base URLs for qa, staging and prod in constants, pick one with a selectedEnv variable and print the login URL.

Show solution
const QA_URL = 'https://qa.shop.test';
const STAGING_URL = 'https://staging.shop.test';
const PROD_URL = 'https://shop.test';
const selectedEnv = 'staging';
const baseUrl = selectedEnv === 'qa' ? QA_URL : selectedEnv === 'staging' ? STAGING_URL : PROD_URL;
const loginUrl = `${baseUrl}/login`;
console.log(loginUrl);

Output

https://staging.shop.test/login

Explanation: constants keep fixed values in one place, and a single variable decides which environment the test uses.

22. Build unique test dataReal-world

Create a unique email for a sign-up test using a fixed runId variable and a username prefix.

Show solution
const prefix = 'qa.user';
const runId = 1730275200;
const email = `${prefix}+${runId}@example.com`;
console.log(email);

Output

qa.user+1730275200@example.com

Explanation: combining a stable prefix with a run ID gives unique but readable test data. In real tests the ID could come from Date.now().

23. Count test resultsReal-world

Use counter variables to tally the statuses ['passed', 'failed', 'passed', 'skipped', 'passed'].

Show solution
const statuses = ['passed', 'failed', 'passed', 'skipped', 'passed'];
let passed = 0, failed = 0, skipped = 0;
for (const status of statuses) {
  if (status === 'passed') passed++;
  else if (status === 'failed') failed++;
  else skipped++;
}
console.log(`Passed: ${passed}, Failed: ${failed}, Skipped: ${skipped}`);

Output

Passed: 3, Failed: 1, Skipped: 1

Explanation: counters declared with let are updated inside the loop. The loop variable status is a fresh const each time.

24. Calculate a pass percentageReal-world

With total = 80 and failed = 6, calculate and print the pass percentage rounded to one decimal place.

Show solution
const total = 80;
const failed = 6;
const passed = total - failed;
const passRate = (passed / total) * 100;
console.log(`Pass rate: ${passRate.toFixed(1)}%`);

Output

Pass rate: 92.5%

Explanation: intermediate variables like passed make the calculation readable. toFixed(1) formats the result.

25. Default timeout with fallbackReal-world

A variable customTimeout may be undefined. Use ?? to fall back to a default of 30000 ms and print the timeout used in both cases.

Show solution
const DEFAULT_TIMEOUT = 30000;
let customTimeout;
console.log('Timeout used:', customTimeout ?? DEFAULT_TIMEOUT);
customTimeout = 60000;
console.log('Timeout used:', customTimeout ?? DEFAULT_TIMEOUT);

Output

Timeout used: 30000
Timeout used: 60000

Explanation: ?? returns the right side only when the left side is null or undefined, which makes it ideal for optional settings.

26. Track login attemptsReal-world

Simulate three failed login attempts with a let counter and lock the account when it reaches MAX_ATTEMPTS = 3.

Show solution
const MAX_ATTEMPTS = 3;
let attempts = 0;
let locked = false;
for (let i = 1; i <= 3; i++) {
  attempts++;
  console.log(`Attempt ${attempts} failed`);
  if (attempts === MAX_ATTEMPTS) locked = true;
}
console.log('Account locked:', locked);

Output

Attempt 1 failed
Attempt 2 failed
Attempt 3 failed
Account locked: true

Explanation: a constant holds the business rule and let variables track state that changes during the scenario.

27. Build a test report lineReal-world

Store the test name, duration in milliseconds and status in variables, then print one formatted report line with the duration in seconds.

Show solution
const testName = 'Checkout with saved card';
const durationMs = 2345;
const status = 'PASSED';
const durationSec = (durationMs / 1000).toFixed(2);
console.log(`[${status}] ${testName} (${durationSec}s)`);

Output

[PASSED] Checkout with saved card (2.35s)

Explanation: separate variables for each piece of data keep the formatting step simple and easy to change.

28. Running cart totalReal-world

Add item prices 499, 1299 and 250 to a running cartTotal, printing the total after each item.

Show solution
let cartTotal = 0;
cartTotal += 499;
console.log('After item 1:', cartTotal);
cartTotal += 1299;
console.log('After item 2:', cartTotal);
cartTotal += 250;
console.log('After item 3:', cartTotal);

Output

After item 1: 499
After item 2: 1798
After item 3: 2048

Explanation: += updates the running total in place, which mirrors how a test checks a cart after each step.

29. Mask a password before loggingReal-world

Store a password in a variable and log a masked version that shows only the last two characters.

Show solution
const password = 'Secr3t!Pass';
const masked = '*'.repeat(password.length - 2) + password.slice(-2);
console.log('Password used:', masked);

Output

Password used: *********ss

Explanation: never log real secrets. A derived variable holds a safe version for logs and reports.

30. Read settings with fallbacksReal-world

Given envVars = { BASE_URL: 'https://qa.app.test' }, read BASE_URL and WORKERS into variables, defaulting WORKERS to 2.

Show solution
const envVars = { BASE_URL: 'https://qa.app.test' };
const baseUrl = envVars.BASE_URL ?? 'http://localhost:3000';
const workers = Number(envVars.WORKERS ?? 2);
console.log('baseUrl:', baseUrl);
console.log('workers:', workers);

Output

baseUrl: https://qa.app.test
workers: 2

Explanation: tests often read process.env, where values may be missing. Defaults keep the run predictable.

31. Destructure test data into variablesReal-world

Unpack username, password and an optional role (default 'viewer') from a test-data object.

Show solution
const testUser = { username: 'qa_tester', password: 'P@ss123' };
const { username, password, role = 'viewer' } = testUser;
console.log(username, role);
console.log('Password length:', password.length);

Output

qa_tester viewer
Password length: 7

Explanation: object destructuring creates several variables at once and can supply defaults for missing properties.

32. Rename while destructuringReal-world

An API returns { id: 7, full_name: 'Neha Sharma' }. Store the values in camelCase variables userId and fullName.

Show solution
const apiUser = { id: 7, full_name: 'Neha Sharma' };
const { id: userId, full_name: fullName } = apiUser;
console.log(`User #${userId}: ${fullName}`);

Output

User #7: Neha Sharma

Explanation: property: newName in destructuring renames a value, which keeps your code in camelCase even when an API uses snake_case.

Keep Practising

Leave a Comment