Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Use the link inside the card, not the card itself. When Bootstrap marks that anchor with stretched-link, click it with Puppeteer’s Locator API:
await page.locator('.card a.stretched-link').click();
Bootstrap expands the anchor’s hit area with a CSS pseudo-element; it does not create a separate, clickable card element. Selecting the semantic anchor gives your test the same target a keyboard or screen-reader user would activate.
What Bootstrap actually makes clickable
A typical Bootstrap card puts the stretched link inside the card body:
<div class="card">
<div class="card-body">
<h3 class="card-title">Deploy guide</h3>
<p class="card-text">Read the deployment steps.</p>
<a href="/docs/deploy" class="stretched-link">Read the guide</a>
</div>
</div>
The card is positioned so the link’s ::after pseudo-element can cover its containing block. The visible text remains the real anchor, while clicks on the covered card area are routed to that anchor. Bootstrap’s documented pattern is therefore a nested link with stretched-link, not a click handler attached to .card.
Free tools Windows power users keep installed
One-click scans. No signup required.
#1 Best Overall
Bootstrap 5.0 and 4.4 documentation describe this pattern. Check the documentation and CSS version that matches your installed Bootstrap package: custom styles, a framework upgrade, or a different card structure can change the containing block.
Recommended Puppeteer implementation
Click the nested anchor with a Locator
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({headless: true});
const page = await browser.newPage();
await page.goto('https://example.com/cards', {waitUntil: 'domcontentloaded'});
await page.locator('.card a.stretched-link').click();
console.log('URL after click:', page.url());
await browser.close();
Puppeteer’s current page-interactions guide (shown as version 25.12.0) recommends Locators for normal interaction. A Locator waits for the element to exist and checks that it is in the viewport, visible, enabled, and has a stable bounding box before clicking. Those checks remove much of the timing code commonly needed with older selector-based tests.
Make the selector specific when there are several cards
If a page contains many cards, a broad selector can click the first matching link. Scope the Locator to the card whose content identifies the intended record:
const card = page.locator('.card').filter({hasText: 'Deploy guide'});
await card.locator('a.stretched-link').click();
Alternatively, add a stable test attribute to your markup:
Recommended Free Tools
<article class="card" data-testid="project-card-42">
<a class="stretched-link" href="/projects/42">Project 42</a>
</article>
await page.locator('[data-testid="project-card-42"] a.stretched-link').click();
Keep the selector tied to the actual DOM. If the card has no stretched-link anchor, inspect the markup and select the link or control that is supposed to respond; do not assume every Bootstrap card is clickable.
Rank #2
Waiting for navigation without a race
When the click loads another document, begin waiting and clicking in the same Promise.all. Registering the navigation wait after starting the click can miss a fast navigation.
const [response] = await Promise.all([
page.waitForNavigation({waitUntil: 'networkidle2'}),
page.locator('.card a.stretched-link').click(),
]);
if (!response) {
throw new Error('The click did not produce a document navigation');
}
if (page.url() !== 'https://example.com/docs/deploy') {
throw new Error(`Unexpected URL: ${page.url()}`);
}
Use domcontentloaded or the default lifecycle when the site keeps long-lived connections that prevent networkidle2 from settling. For single-page applications, a click may update history or render content without a document navigation; in that case, wait for the URL or a destination element instead:
await page.locator('.card a.stretched-link').click();
await page.waitForFunction(() => location.pathname === '/docs/deploy');
await page.locator('main h1').wait();
Always assert an observable result—URL, heading, or a destination component—rather than treating a completed click call as proof that the application worked.
Locator click versus page.click()
| Approach | Behavior | When to use it |
|---|---|---|
page.locator(selector).click() |
Recommended interaction API; waits for presence, visibility, viewport, enabled state, and a stable bounding box. | Normal tests and card links. |
page.click(selector) |
Finds the matching element, scrolls it into view, and clicks its center; throws if no match exists. | Tests that intentionally exercise this lower-level API behavior. |
Both APIs target the element matched by the selector. Neither turns the card into a new semantic control. For a stretched card, target the anchor so the test verifies the same action exposed to users.
Making the whole card clickable correctly
Use one primary stretched target
Give a card one main stretched link. Multiple links or tap targets competing inside the same stretched region are discouraged by Bootstrap because stacking and hit testing become ambiguous. If a card also contains “Edit,” “Delete,” or a menu button, test those controls separately and ensure they sit above the stretched pseudo-element in the intended stacking order.
Check the containing block
The pseudo-element stretches only within its containing block. Positioning, transforms, perspective, will-change, and some filters can establish new containing blocks. An inner transformed wrapper can therefore shrink the area that appears clickable or redirect it to an unexpected region.
/* A predictable card boundary */
.card {
position: relative;
}
/* Inspect carefully: this can create a new containing block */
.card-media {
transform: translateZ(0);
}
When a click near the card edge fails, inspect computed styles and the element rectangles in DevTools. Remove an unnecessary transform, move it to a non-containing wrapper, or adjust the card structure so the anchor’s pseudo-element has the intended containing block. Keep the Bootstrap stylesheet loaded; without its stretched-link rules, the class is only a class name.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Do not replace semantic links with a card click handler
An <a> supplies keyboard activation, focus behavior, URL semantics, and assistive-technology information. A JavaScript onclick on a <div> can look equivalent visually while producing a less accessible and harder-to-test interface.
Complete runnable test example
import puppeteer from 'puppeteer';
(async () => {
const browser = await puppeteer.launch({headless: true});
try {
const page = await browser.newPage();
await page.goto('https://example.com/cards', {
waitUntil: 'domcontentloaded',
timeout: 30000
});
const card = page.locator('.card').filter({hasText: 'Deploy guide'});
await card.locator('a.stretched-link').wait();
const [response] = await Promise.all([
page.waitForNavigation({waitUntil: 'domcontentloaded', timeout: 30000}),
card.locator('a.stretched-link').click()
]);
if (!response || !page.url().endsWith('/docs/deploy')) {
throw new Error(`Unexpected destination: ${page.url()}`);
}
await page.locator('main h1').wait();
console.log('Card navigation passed');
} finally {
await browser.close();
}
})();
Replace the example URL, card text, and destination assertion with values from your application. If your page uses a client-side router, remove waitForNavigation and wait for the route or destination content instead.
Troubleshooting failed card clicks
“No element found” or a Locator timeout
- Confirm the card has an
<a>withstretched-link; the class may be on a different element or omitted. - Verify the selector and card text, including capitalization and whitespace.
- Wait for the page’s data-rendering condition, not just the initial document load.
- Check whether the card is inside an iframe. Select the correct frame before creating the Locator.
The click is intercepted or the wrong control fires
- Look for a cookie banner, modal, sticky header, or overlay covering the card.
- Check z-index and stacking contexts around secondary buttons.
- Inspect transforms, filters, and positioned descendants that may alter the stretched link’s containing block.
- Keep one primary stretched target and verify secondary controls independently.
Navigation wait hangs
- The click may be an SPA route change rather than a document navigation; wait for a URL or destination element.
- The page may keep WebSocket or analytics connections open; use
domcontentloadedinstead of a network-idle condition. - Start
page.waitForNavigation()and the click together inPromise.all.
The test passes but the page did not change
A completed click only means Puppeteer dispatched the action. Assert the expected URL, heading, or application state. Also verify that the anchor’s href is correct and that no event handler calls preventDefault() unexpectedly.
Rank #4
Headless and headed runs differ
Set the same viewport, device scale, authentication state, and page content in both modes. Responsive CSS can move controls or create an overlay at a different width. Capture a screenshot on failure and inspect the actual layout rather than adding arbitrary delays.
Reliability and performance practices
- Reuse one browser process and create isolated pages or contexts for multiple card tests.
- Prefer stable attributes such as
data-testidover selectors tied to decorative class names. - Use explicit, bounded navigation and element timeouts so a broken page fails with a useful message.
- Wait on meaningful states—visible destination content, a route, or a network response your app controls—instead of fixed sleeps.
- Record the URL, selector, viewport, and a failure screenshot when diagnosing intermittent results.
- Use a single main link per stretched card and keep card content deterministic in test fixtures.
Or skip the browser setup
If your goal is a clean image or PDF of a card page rather than an interaction test, ScreenshotNeo provides a website screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.
One-call cURL example (see the ScreenshotNeo documentation):
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Every plan includes the features: full-page and element capture, device and retina settings, dark mode, PDF controls, custom CSS and JavaScript, clicks, waits, request blocking, headers, cookies, user agents, timezone and geolocation, transparent backgrounds, resizing, TTL caching, signed links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage reporting, and an OpenAPI specification. The free plan includes 1,000 shots each month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
FAQ
Can I click the card with page.locator('.card').click()?
Only if the card element itself is the intended interactive target and the layout makes that click valid. With Bootstrap’s stretched-link pattern, the semantic target is the nested anchor, so select that anchor.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsDoes stretched-link work without Bootstrap CSS?
No. The class relies on Bootstrap’s styles for the pseudo-element and positioning behavior. Confirm that the stylesheet for your Bootstrap version is loaded.
Best Value
- Used Book in Good Condition
What if the card opens a new tab?
Listen for the new page or target before clicking, then assert its URL. Do not use a document-navigation wait on the original page when the link’s target is a separate tab.
Frequently Asked Questions
Can I click the card with page.locator(‘.card’).click()?
Only when the card itself is the intended interactive element. For Bootstrap’s stretched-link pattern, click the nested anchor.
Does stretched-link work without Bootstrap CSS?
No. Its expanded hit area comes from Bootstrap’s pseudo-element and positioning styles.
What if the card opens a new tab?
Wait for the new page or target before clicking, then assert that page’s URL instead of waiting for navigation on the original page.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




