Practise JavaScript strings 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.
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 Strings lesson first.
- Beginner programs (1–10)
- Intermediate programs (11–20)
- Real-world QA scenario programs (21–32)
JavaScript Beginner Programs
1. String lengthBeginner
Print the length of 'Playwright Testing'.
Show solution
const title = 'Playwright Testing';
console.log(title.length);
Output
18
Explanation: length counts every character, including spaces.
2. Upper and lower caseBeginner
Convert 'Login Page' to upper case and lower case.
Show solution
const text = 'Login Page';
console.log(text.toUpperCase());
console.log(text.toLowerCase());
Output
LOGIN PAGE
login page
Explanation: case methods return new strings. The original string is unchanged.
3. First and last characterBeginner
Print the first and last character of 'automation'.
Show solution
const word = 'automation';
console.log(word[0]);
console.log(word.at(-1));
Output
a
n
Explanation: index 0 is the first character, and at(-1) reads from the end.
4. Trim whitespaceBeginner
Remove spaces around ' qa@example.com '.
Show solution
const raw = ' qa@example.com ';
console.log(`[${raw.trim()}]`);
console.log(`[${raw.trimStart()}]`);
Output
[qa@example.com]
[qa@example.com ]
Explanation: trim removes whitespace from both ends. trimStart and trimEnd remove one side only.
5. Check if a string contains textBeginner
Check whether 'Order placed successfully' contains 'success' and 'failed'.
Show solution
const message = 'Order placed successfully';
console.log(message.includes('success'));
console.log(message.includes('failed'));
Output
true
false
Explanation: includes returns true or false. It is case-sensitive.
6. startsWith and endsWithBeginner
Check whether a URL starts with https:// and ends with /login.
Show solution
const url = 'https://qa.shop.test/login';
console.log(url.startsWith('https://'));
console.log(url.endsWith('/login'));
Output
true
true
Explanation: these methods check the beginning or end of a string without regular expressions.
7. Extract part of a stringBeginner
Extract 'Play' and 'wright' from 'Playwright' with slice.
Show solution
const tool = 'Playwright';
console.log(tool.slice(0, 4));
console.log(tool.slice(4));
console.log(tool.slice(-6));
Output
Play
wright
wright
Explanation: slice(start, end) stops before end. Negative numbers count from the end.
8. Replace textBeginner
Replace 'staging' with 'qa' in a URL, then replace every space with a dash in a title.
Show solution
const url = 'https://staging.shop.test/staging/home';
console.log(url.replace('staging', 'qa'));
console.log(url.replaceAll('staging', 'qa'));
console.log('My First Test'.replaceAll(' ', '-'));
Output
https://qa.shop.test/staging/home
https://qa.shop.test/qa/home
My-First-Test
Explanation: replace changes only the first match. replaceAll changes every match.
9. Split a sentence into wordsBeginner
Split 'run tests in parallel' into words and count them.
Show solution
const sentence = 'run tests in parallel';
const words = sentence.split(' ');
console.log(words);
console.log('Word count:', words.length);
Output
[ 'run', 'tests', 'in', 'parallel' ]
Word count: 4
Explanation: split turns a string into an array using a separator.
10. Repeat and padBeginner
Print a divider of 20 dashes and pad test IDs to 4 digits.
Show solution
console.log('-'.repeat(20));
for (const id of [7, 42, 315]) console.log('TC-' + String(id).padStart(4, '0'));
Output
--------------------
TC-0007
TC-0042
TC-0315
Explanation: repeat duplicates a string, and padStart fills it to a fixed length.
JavaScript Intermediate Programs
11. Reverse a stringIntermediate
Reverse 'Playwright'.
Show solution
const reversed = 'Playwright'.split('').reverse().join('');
console.log(reversed);
Output
thgirwyalP
Explanation: strings have no reverse, so split into characters, reverse the array and join it again.
12. Palindrome check ignoring case and spacesIntermediate
Check whether 'Never odd or even' is a palindrome.
Show solution
const text = 'Never odd or even';
const clean = text.toLowerCase().replace(/[^a-z0-9]/g, '');
const isPalindrome = clean === [...clean].reverse().join('');
console.log(clean, isPalindrome);
Output
neveroddoreven true
Explanation: normalise the text first (lower case, letters only), then compare it with its reverse.
13. Count occurrences of a characterIntermediate
Count how many times 't' appears in 'test automation tutorial'.
Show solution
const text = 'test automation tutorial';
let count = 0;
for (const ch of text) if (ch === 't') count++;
console.log(count);
console.log(text.split('t').length - 1);
Output
6
6
Explanation: you can loop over characters, or split on the character and count the pieces minus one.
14. Capitalise each wordIntermediate
Convert 'checkout with saved card' to title case.
Show solution
const title = 'checkout with saved card'
.split(' ')
.map(word => word[0].toUpperCase() + word.slice(1))
.join(' ');
console.log(title);
Output
Checkout With Saved Card
Explanation: split into words, capitalise the first letter of each, and join them back.
15. Character frequency mapIntermediate
Count each character in 'banana'.
Show solution
const freq = {};
for (const ch of 'banana') freq[ch] = (freq[ch] || 0) + 1;
console.log(freq);
Output
{ b: 1, a: 3, n: 2 }
Explanation: an object works as a counter, with each character as a key.
16. Anagram checkIntermediate
Check whether 'listen' and 'silent' are anagrams.
Show solution
const normalise = s => [...s.toLowerCase()].sort().join('');
console.log(normalise('listen') === normalise('silent'));
console.log(normalise('test') === normalise('sets'));
Output
true
false
Explanation: anagrams contain the same letters, so their sorted characters match.
17. camelCase to kebab-caseIntermediate
Convert 'loginButtonText' to 'login-button-text'.
Show solution
const camel = 'loginButtonText';
const kebab = camel.replace(/([A-Z])/g, '-$1').toLowerCase();
console.log(kebab);
Output
login-button-text
Explanation: a regular expression inserts a dash before each capital letter, and lower-casing finishes the job.
18. Longest wordIntermediate
Find the longest word in 'Playwright makes cross browser testing reliable'.
Show solution
const words = 'Playwright makes cross browser testing reliable'.split(' ');
let longest = '';
for (const w of words) if (w.length > longest.length) longest = w;
console.log(longest, longest.length);
Output
Playwright 10
Explanation: track the best word while looping, replacing it only when a longer one appears.
19. Truncate long textIntermediate
Write truncate(text, max) that adds ... when text is longer than max.
Show solution
const truncate = (text, max) => (text.length > max ? text.slice(0, max - 3) + '...' : text);
console.log(truncate('Short title', 20));
console.log(truncate('A very long product name that overflows', 20));
Output
Short title
A very long produ...
Explanation: UI tests often check that long names are cut off, so knowing the exact rule helps.
20. Compare strings ignoring caseIntermediate
Compare 'Submit' and 'SUBMIT' case-insensitively in two ways.
Show solution
const a = 'Submit', b = 'SUBMIT';
console.log(a === b);
console.log(a.toLowerCase() === b.toLowerCase());
console.log(a.localeCompare(b, undefined, { sensitivity: 'accent' }) === 0);
Output
false
true
true
Explanation: normalising case, or localeCompare with a sensitivity option, ignores letter case.
JavaScript Real-World QA Scenario Programs
21. Validate an email formatReal-world
Check a list of emails against a simple pattern.
Show solution
const pattern = /^[^\s@]+@[^\s@]+\.[a-z]{2,}$/i;
for (const email of ['qa@example.com', 'qa@example', 'qa example@test.com', 'QA@Shop.IN']) {
console.log(email.padEnd(20), pattern.test(email) ? 'valid' : 'invalid');
}
Output
qa@example.com valid
qa@example invalid
qa example@test.com invalid
QA@Shop.IN valid
Explanation: a regular expression describes the allowed format. padEnd aligns the output in columns.
22. Extract the order numberReal-world
Extract ORD-58213 from the confirmation text.
Show solution
const confirmation = 'Thank you! Your order ORD-58213 has been placed.';
const match = confirmation.match(/ORD-\d+/);
console.log(match ? match[0] : 'Not found');
Output
ORD-58213
Explanation: match returns the matched text, so tests can reuse dynamic values shown in the UI.
23. Mask a card numberReal-world
Show only the last 4 digits of '4111 1111 1111 1234'.
Show solution
const card = '4111 1111 1111 1234';
const digits = card.replace(/\s/g, '');
const masked = '**** **** **** ' + digits.slice(-4);
console.log(masked);
Output
**** **** **** 1234
Explanation: remove spaces first so the last four characters are always digits.
24. Build a slug from a titleReal-world
Turn ' Playwright: Getting Started (2026)! ' into 'playwright-getting-started-2026'.
Show solution
const title = ' Playwright: Getting Started (2026)! ';
const slug = title.trim().toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
console.log(slug);
Output
playwright-getting-started-2026
Explanation: replace every run of non-alphanumeric characters with one dash, then trim dashes from the ends.
25. Parse a key=value cookie stringReal-world
Turn 'session=abc123; theme=dark; lang=en' into an object.
Show solution
const cookieText = 'session=abc123; theme=dark; lang=en';
const cookies = {};
for (const part of cookieText.split('; ')) {
const [key, value] = part.split('=');
cookies[key] = value;
}
console.log(cookies);
Output
{ session: 'abc123', theme: 'dark', lang: 'en' }
Explanation: split into pairs, then split each pair at =.
26. Normalise whitespace in UI textReal-world
Collapse extra spaces and line breaks in ' Total:\n ₹1,299 '.
Show solution
const uiText = ' Total:\n ₹1,299 ';
const normalised = uiText.replace(/\s+/g, ' ').trim();
console.log(normalised);
Output
Total: ₹1,299
Explanation: page text often contains line breaks and indentation. Playwright’s toHaveText normalises whitespace the same way.
27. Check the URL path and queryReal-world
Read the path and the q parameter from a search URL.
Show solution
const url = new URL('https://shop.test/search?q=wireless%20mouse&page=2');
console.log(url.pathname);
console.log(url.searchParams.get('q'));
console.log(url.searchParams.get('page'));
Output
/search
wireless mouse
2
Explanation: the URL class parses URLs and decodes values such as %20, which is safer than slicing strings.
28. Template literal reportReal-world
Build a multi-line test report with a template literal.
Show solution
const name = 'Checkout';
const passed = 18, failed = 2;
const report = `Suite: ${name}
Passed: ${passed}
Failed: ${failed}
Status: ${failed === 0 ? 'GREEN' : 'RED'}`;
console.log(report);
Output
Suite: Checkout
Passed: 18
Failed: 2
Status: RED
Explanation: template literals keep line breaks and can include expressions such as ternaries.
29. Compare expected and actual textReal-world
Report the first position where two strings differ.
Show solution
function firstDiff(a, b) {
const len = Math.max(a.length, b.length);
for (let i = 0; i < len; i++) if (a[i] !== b[i]) return i;
return -1;
}
const expected = 'Welcome back, Asha';
const actual = 'Welcome back, Asha!';
const i = firstDiff(expected, actual);
console.log(i === -1 ? 'Texts match' : `Differs at index ${i}: '${expected[i] ?? ''}' vs '${actual[i] ?? ''}'`);
Output
Differs at index 18: '' vs '!'
Explanation: pinpointing the first difference makes text-assertion failures much quicker to debug.
30. Extract all hashtagsReal-world
Find all hashtags in a social post.
Show solution
const post = 'Learning #Playwright with #TypeScript for #QA automation';
const tags = post.match(/#\w+/g) || [];
console.log(tags.join(', '));
console.log(tags.length);
Output
#Playwright, #TypeScript, #QA
3
Explanation: the g flag returns every match. || [] avoids errors when nothing matches.
31. Format a name for displayReal-world
Convert ' ASHA sharma ' into 'Asha Sharma'.
Show solution
const raw = ' ASHA sharma ';
const display = raw
.trim()
.split(/\s+/)
.map(part => part[0].toUpperCase() + part.slice(1).toLowerCase())
.join(' ');
console.log(display);
Output
Asha Sharma
Explanation: splitting on \s+ handles any number of spaces between words.
32. Count words in a reviewReal-world
Count the words in a review, ignoring extra spaces, and check a 10-word minimum.
Show solution
const review = ' Great product, fast delivery and very good packaging ';
const wordCount = review.trim().split(/\s+/).length;
console.log('Words:', wordCount);
console.log(wordCount >= 10 ? 'Accepted' : 'Too short');
Output
Words: 8
Too short
Explanation: trimming first avoids empty strings at the ends being counted as words.