BugBlitz · Workshop Materials

Bug Report

The bugs your team is tackling today. Each entry includes the reported symptom, reproduction steps, a working comparison case, and the acceptance criteria a fix must meet.

Release-Day Priorities

These tickets come from several release-day stakeholders—some brief, some deeply technical. As a team, weigh what’s reported, what’s missing, and how the reporter’s perspective shapes the report.

Stuck? Each bug report entry includes optional hints you can reveal one at a time.

Goal 1: Triage with your team

  1. Review bugs. Read through the incoming bug reports as a team. What was reported, who reported it, and where in the app does it happen?
  2. Assess impact and effort. Who is affected, how often, and what can’t they do? Consider customer and business impact, available workarounds, and the time needed to address it. Adjust the starting effort estimate as you learn more.
    Tip: reproduce the bug to better understand its impact.
  3. Agree on priority and choose a bug. Assign P1, P2, or P3 and explain why. Which bug should your team tackle first, given its impact and the time available?
Filter bugs
|
Showing 0 of 0 bugs

Triage Matrix

Compare priority × effort to choose what to tackle first.

Your bug reporters have provided initial effort estimates. Feel free to adjust them based on your team’s experience and what you discover, but assigning priority to the bugs should be your main focus.

Select a bug to read its report. Drag it from Needs triage into the matrix, or edit its values in the Bug Directory. Drag the bug back to Needs triage to clear its priority.Set priority and effort in the Bug Directory. The matrix updates automatically.

About severity and priority

Low Effort Medium Effort High Effort
P1 (High)
Low effort
Quick Win — do first
Medium effort
Do now; assign your best debugger
High effort
Ship a workaround, schedule the real fix
P2 (Medium)
Low effort
Slot in this sprint
Medium effort
Next sprint
High effort
Ship a workaround now; split the real fix across sprints
P3 (Low)
Low effort
Batch with the next release
Medium effort
Backlog
High effort
Assign an owner and revisit later

Needs triage

Set missing values in the Bug Directory above to place these bugs in the matrix.

Goal 2: Solve bugs together

Based on your triage results, choose your first bug and then work through these steps:

  1. Reproduce the bug. Follow the report’s steps in the app. Agree on what should happen and what actually happens.
  2. Investigate and choose an approach. Use the code, DevTools, and optionally AI to trace the cause. Decide whether a fix or workaround fits your remaining time.
  3. Make and verify your change. Repeat the reproduction steps and then test related actions to make sure the user flow works as expected.
  4. Share with your team. Explain what you changed, why you chose that approach, and anything still unresolved.

Have time for another bug? Return to your triage results, choose your next prioritized bug, and repeat these steps.

💡 You don’t need to fix every bug—focus on making and verifying changes you can explain.

CSS Bug
Device-Specific

Welcome offer is overlapped on mobile

Reported by Design

On mobile, the cookie notice partially overlaps the welcome offer and its buttons, making the layout look crowded and unfinished. The desktop layout looks fine. On smaller screens, these elements should have clear spacing and fit together cleanly, with the close button and “Start shopping” action fully visible and easy to tap.

Reproduction Steps
  1. Open the home page at a phone-sized viewport (or on a mobile device).
  2. Refresh the page so the welcome offer and cookie notice appear together.
  3. Notice how the cookie notice overlaps the welcome offer, including parts of its buttons, disrupting the spacing and visual hierarchy.
  4. Check whether the whole welcome offer is clearly visible and visually separated from the cookie notice.
Your mission: Investigate why the welcome offer and cookie notice compete for space on mobile, and fix the experience so both are functional and can be dismissed in either order.
Need a hint?

Reveal one hint at a time. Stop whenever you have enough to try your next step.

Hint 1 of 3 · Where to look

On the home page, open DevTools and enable the device toolbar (phone/tablet icon). Choose a narrow phone viewport and refresh with the welcome offer and cookie notice visible. Compare with a desktop width and try both panels’ buttons. At what screen size do the panels start competing for space?

Hint 2 of 3 · What to investigate

In DevTools → Elements, use the element picker to inspect each panel. In Styles, compare their positioning rules and bottom offsets; check their rendered heights too. Edit values directly in DevTools before changing the codebase, and try a width where the notice text wraps. Which positioning change makes both panels’ buttons accessible?

Hint 3 of 3 · Another clue

Find the mobile rule for .offer-popover in welcome-offer.component.scss. Move your successful DevTools experiment into the stylesheet, then reload because DevTools edits are temporary. Check narrow widths, enlarged text, and dismissing either panel first. How much bottom clearance does the offer need to stay above the cookie notice?

Interaction Bug

"Charged twice for the same order?"

Before you startThis exercise isn’t supported with Mock API in StackBlitz. Choose another bug, or run the project locally to try this one.

Reported by Customer Support

Getting a wave of complaints from customers saying they placed a single order but were charged twice. A couple of them mentioned they "clicked the button twice because nothing happened the first time." The My Orders tab shows duplicate orders when they search using their email. Passing it to engineering to look at.

Your mission: Reproduce the duplicate charge yourself, trace the checkout submit flow, and propose a fix that prevents a second checkout request from firing while the first one is still processing.
Need a hint?

Using Mock API in StackBlitz? Choose another bug or run the project locally.

Reveal one hint at a time. Stop whenever you have enough to try your next step.

Hint 1 of 3 · Where to look

On checkout, use a different test email for each attempt so earlier orders do not confuse the result. Compare one deliberate click on Place Order with two quick clicks. In My Orders, search each email and compare the new orders’ items and totals. How many orders appeared after one click versus two quick clicks?

Hint 2 of 3 · What to investigate

Open DevTools → Network, enable Preserve log, filter to Fetch/XHR, and select a slow throttling preset. Chrome DevTools throttling guide ↗ Repeat the rapid clicks and compare the order POST requests’ Payload tabs. In Elements, inspect the button while the first request is pending. Can another submission start before the first request finishes?

Hint 3 of 3 · Another clue

Find the submit handler and submitting state in checkout.component.ts, and the Place Order button in checkout.component.html. After making a change, verify one order for rapid clicks and that a failed request allows a retry; you can submit while Network is Offline, restore the connection, and retry. Restore normal throttling afterward. How could submitting both disable the button and guard the handler, while always allowing another attempt after failure?

Form Validation Bug

Checkout error message is unhelpful — hurting conversion

Reported by Product Manager

When a shopper submits checkout with a missing required field, they get one generic "Please fill in all fields" message with no indication of which field is the problem. Session replays show people re-checking every input in frustration; funnel data shows abandonment spikes at this step. Fixing this should be a straightforward conversion win.

What good looks like
  • Each missing required field is called out inline, with a message that names the field and what's expected.
  • Valid fields don't get flagged as errors.
  • Successful submissions behave exactly as they do today.
Your mission: Trace the current validation flow, then propose a fix that surfaces field-level errors so users know exactly what to fix.
Need a hint?

Reveal one hint at a time. Stop whenever you have enough to try your next step.

Hint 1 of 3 · Where to look

On checkout, use a valid US address to avoid the separate international postal-code issue. Clear one required field and submit, then repeat with a different field. Leave two fields empty and correct only one. What does the feedback tell you about which fields still need attention?

Hint 2 of 3 · What to investigate

Open DevTools → Network, filter to Fetch/XHR, and repeat an incomplete submission to see whether an order request is sent. In Elements, inspect the empty input and the error message. Search the project for the exact displayed error text. Where is the message chosen, and does that code keep track of which fields failed?

Hint 3 of 3 · Another clue

In checkout.component.ts, inspect the required-field checks; in checkout.component.html, find where the error is rendered. After your change, verify that correcting a field clears its error on revalidation and that valid checkout still works. Keep optional-region rules consistent with the State/Province report. How could you collect errors by field, display each beside its input, and associate the message with that input for accessibility?

Form Validation Bug

International customers can't check out

Reported by Director

Sales flagged this — orders from non-US customers aren't going through. Canada, UK, and Japan all seeing it. Would like a triage plan by end of day: whether this is a same-day fix or something that needs a temporary workaround while a proper fix ships.

A Canadian customer reported that the following address wasn't accepted:

Street address
100 Queen's Park
City
Toronto
Province
ON
Postal code
M5S 2C6
Country
Canada
Your mission: Reproduce the checkout failure with a valid international postal code, trace the validation logic, and propose a fix that supports the selected country without breaking US ZIP validation.
Need a hint?

Reveal one hint at a time. Stop whenever you have enough to try your next step.

Hint 1 of 3 · Where to look

On checkout, complete the Canadian example from the report and note the exact error. Compare the country selection, postal-code label, and message. Try a valid and an invalid format for both Canada and the US, keeping other required fields filled. Which inputs are rejected, and does the message describe the country you selected?

Hint 2 of 3 · What to investigate

In DevTools → Network, filter to Fetch/XHR and repeat the Canadian submission. If an order POST appears, inspect its Payload and Response; if none appears, investigate the form’s validation. Search for the exact postal-code error text and inspect the condition that produces it. Does that check use the selected country?

Hint 3 of 3 · Another clue

In checkout.component.ts, set a Sources breakpoint at postal-code validation and inspect form.country, form.zip, and the pattern being tested. Retest valid and invalid formats after your change, distinguishing region errors from postal-code errors. How could the selected country determine both the validation rule and the format example shown when validation fails?

Form Validation Bug

State/Province selection carries over when the country changes

Reported by QA Tester

A shopper changes the selected country in the checkout form, but a previously chosen state or province value silently carries over, so the form submits with a state that doesn't belong to the new country.

Reproduction Steps
  1. Add any item to the cart and navigate to the checkout page.
  2. Select United States as the country and pick a state (e.g., California).
  3. Change the country to a different one (e.g., Germany or United Kingdom).
  4. Fill in the remaining fields and submit the form or inspect the form data.
  5. Observe that the state field still holds the previously chosen value ("CA") even though it makes no sense for the new country.
Comparison Case
  1. Reload the page and pick a country only once before submitting.
  2. Observe that the state value corresponds correctly to the selected country.
Acceptance Criteria
  1. Changing the country clears any previously selected state/province value.
  2. The state field re-renders correctly (select vs. free-text input) based on the new country's regions.
  3. When State/Province is required for the selected country, the required-field check catches the empty value after a country change instead of allowing a stale value to slip through. Otherwise, the field is optional or hidden and an empty value does not block submission.
  4. No regressions to the initial country selection flow.
Your mission: Investigate what happens to form state when the country changes, and propose a fix that resets the state whenever the country selection changes.
Need a hint?

Reveal one hint at a time. Stop whenever you have enough to try your next step.

Hint 1 of 3 · Where to look

On checkout, select a US state, then switch to Canada. Repeat with France and compare with choosing a country once after a refresh. Note whether State/Province is a dropdown or text input and whether the old choice remains visible. Does a change in the displayed control tell you whether the previous value was cleared?

Hint 2 of 3 · What to investigate

In DevTools → Elements, inspect the region options, label, and required attribute. Compare an empty region with a selected region for Canada, then try an empty region for France. Note which validation check blocks submission—the separate postal-code bug can also reject an address. Do the displayed choices, stored value, and required-field behavior agree?

Hint 3 of 3 · Another clue

Find onCountryChange in checkout.component.ts and pause there with a Sources breakpoint. Step through while watching form.state, then inspect the region validation and its template’s required binding. Verify the form value even if the postal-code bug still blocks submission. How could changing countries clear the old region and apply a consistent rule for when a new region is required?

Interaction Bug

"The Add to Cart button is broken on some plants"

Reported by Customer Support

Customers keep messaging in convinced the "Add to Cart" button is broken on certain products — they click it and nothing happens. Those cards are faded and have an "Out of Stock" badge in the top-right corner, but shoppers seem to miss it and the button still says "Add to Cart." Can we make the availability clearer? People shouldn't have to contact us to figure out that a plant is out of stock.

Your mission: The reporter has told you what shoppers think is happening; work out what's actually happening in the UI, then propose a fix that makes the sold-out state obvious without breaking normal Add to Cart behavior on in-stock items.
Need a hint?

Reveal one hint at a time. Stop whenever you have enough to try your next step.

Hint 1 of 2 · Where to look

On the plant listing, right-click Add to Cart for an available product and a sold-out product and choose Inspect. In DevTools → Elements, compare the disabled attribute, visible text, and accessible name. What tells the browser that one button is unavailable, and what tells the shopper why?

Hint 2 of 2 · Another clue

Inspect the stock binding and button text in product-card.component.html. Try disabled-button styling in DevTools → Styles before updating product-card.component.scss. Verify that available products still add to the cart and sold-out products stay unavailable. How could the button’s label, accessible name, and styling explain its stock status at the point where the shopper tries to act?

Data Bug

One of the product cards has a missing image

Reported by Product Manager

One of the product cards on the plant listing is showing a broken image — the rest of the card looks fine but there's no photo. Looks bad for something a shopper sees first. Low priority relative to the checkout issues, but let's not ship the release with a broken image visible on the homepage.

Your mission: Find the affected product, trace the bad URL back to where the data comes from, and propose a fix that both restores the image and hardens the UI against a future broken URL slipping through.
Need a hint?

Reveal one hint at a time. Stop whenever you have enough to try your next step.

Hint 1 of 2 · Where to look

On the plant listing, open DevTools → Network, select the Img filter, and reload. Select the failed image request and find its Request URL in Headers. Compare that URL with a working image request. What differs between the addresses the browser is trying to load?

Hint 2 of 2 · Another clue

Search product-images.ts for the failed URL and compare its hostname with the working image URLs. Try correcting it, then reload to check the photo. For future failures, inspect the image element in product-card.component.html and the existing placeholder returned by resolveProductImage(null). How could you correct this image’s address and show a placeholder if another image fails, without repeatedly retrying a failed placeholder?

Interaction Bug
CSS Bug

Clear Cart dialog locks the page

Reported by Product Manager

After dismissing the Clear Cart dialog, customers are unable to click anything on the site and are forced to refresh the page to continue shopping.

Reproduction Steps
  1. Add an item to the cart to open the cart modal.
  2. Click Clear Cart to open the confirmation prompt.
  3. Click Keep Items or Clear Cart to close the prompt.
  4. If you try to click any product or navigation link on the page, it has no effect.
Acceptance Criteria
  1. Confirming "Clear Cart" successfully empties all items from the cart.
  2. Closing or confirming the dialog leaves the page fully clickable so customers can keep browsing without refreshing.
Your mission: Reproduce the issue by interacting with the confirmation dialog and restore normal page interaction.
Need a hint?

Reveal one hint at a time. Stop whenever you have enough to try your next step.

Hint 1 of 3 · Where to look

Reproduce the issue by opening Clear Cart and choosing Keep Items. Leave the page in its unresponsive state. Open DevTools → Elements and use the element picker over a button or link that no longer responds. What element does it select?

Hint 2 of 3 · What to investigate

In Elements, inspect the selected element and its surrounding DOM. Use the page highlight to see how much space it covers, and check its position and dimensions in Styles or Computed. Did DevTools select the button or link you were trying to click? If not, what did it select?

Hint 3 of 3 · Another clue

If you find an element covering the page, temporarily add display: none in Styles and try clicking again. Search confirmation-dialog.component.ts for where that element is created or attached, then compare opening and closing the dialog. Reload to undo the temporary CSS change, and test cancellation, confirmation, and backdrop dismissal. What should happen to that extra element when the dialog component is destroyed?

Data Bug

Same promo code can be applied multiple times

Reported by QA Tester

A shopper can apply the same promo code repeatedly and receive the discount more than once, driving the cart total down with each duplicate code. It can even push the total below zero.

Reproduction Steps
  1. Add at least one product to the cart and navigate to the cart page (/cart).
  2. Enter a valid promo code (for example GHC2026 or WELCOME10) and click Apply.
  3. The coupon appears in the applied list and the discount is reflected in the total.
  4. Without reloading, enter the same promo code again and click Apply.
  5. Now, the same coupon is listed again (and the discount total increases).
Acceptance Criteria
  1. The same promo code cannot be applied more than once per cart session.
  2. A second attempt shows clear feedback (e.g., "This promo code is already applied.").
  3. discountTotal reflects each distinct coupon at most once.
  4. discountTotal should never exceed the subtotal.
Your mission: Reproduce the issue by applying the same promo code more than once, inspect how applied coupons are tracked across page loads, and propose a fix that prevents stacking the same code multiple times and prevents the total from going below zero.
Need a hint?

Reveal one hint at a time. Stop whenever you have enough to try your next step.

Hint 1 of 3 · Where to look

Open DevTools → Application → Local Storage and select the app’s origin. Inspect cart_coupons before and after applying the same code twice; refresh the storage view if needed. Reload and compare the saved entries with the applied-coupon list. How many entries represent the same coupon, and do they survive a reload?

Hint 2 of 3 · What to investigate

Find applyCoupon in cart.service.ts and follow the checks before it updates the applied-coupon collection. Compare the coupon returned by the lookup with the entries already in that collection. What is checked before adding a coupon, and is an already-applied code treated differently from a new one?

Hint 3 of 3 · Another clue

In applyCoupon, consider returning useful feedback before modifying the collection when the code is already present. Verify valid, invalid, and repeated codes, including capitalization and surrounding spaces; reload to check persistence and confirm discounts cannot exceed the subtotal. How could you recognize equivalent codes before saving another entry and keep the total from falling below zero?

Data Bug

Cart and checkout totals ignore the sale price

Reported by QA Tester

A shopper adds an item marked "On Sale" to their cart. The line-item price in the cart matches the sale price shown on the product card, but the cart Subtotal and Total — and the checkout Order Summary and Place Order button — are calculated from the higher crossed-out price instead of the sale price.

Reproduction Steps
  1. Start with an empty cart and no applied promo codes. Remove items individually if Clear Cart is still broken.
  2. In the header, click Sale (or on the shop page, sort by On Sale) and pick any product showing a "Sale" badge with a strikethrough original price.
  3. Click Add to Cart. The cart modal opens automatically.
  4. In the modal, compare the line-item price against the modal's Total. The total is higher than the line-item price times quantity.
  5. Click View Cart & Checkout. On the cart page, the line item shows the sale price, but the Subtotal and Total use the original (pre-sale) price.
  6. Click Proceed to Checkout. The Order Summary and the Place Order button both show the inflated total.
Comparison Case
  1. Remove the sale item, then add one product without a "Sale" badge. Keep promo codes removed.
  2. Observe that the line-item price, the modal total, the cart Subtotal, and the checkout total all agree.
Acceptance Criteria
  1. Cart-modal total, cart-page Subtotal and Total, and checkout Order Summary all reflect the sale price for items on sale.
  2. Per-line item totals in the cart page and checkout Order Summary agree with the summary Subtotal.
  3. The Place Order button shows the same total as the Order Summary.
  4. Non-sale items (no compare_at_price) are unaffected.
  5. A percentage-based promo code applied on top of a sale item discounts against the sale price, not the crossed-out price.
Your mission: Reproduce the mismatch between the line-item price and the summary total, trace how the cart's subtotal is computed, and propose a fix that honors the sale price consistently across the modal, cart, and checkout.
Need a hint?

Reveal one hint at a time. Stop whenever you have enough to try your next step.

Hint 1 of 3 · Where to look

Start with one sale item, quantity 1, and no promo codes. Compare the line-item amount with the subtotal. Repeat with a regular-price item. Which case adds up correctly?

Hint 2 of 3 · What to investigate

In DevTools → Network, inspect the product request’s Preview or Response and find the sale product’s price information. Compare it with the line-item amount and subtotal you observed at quantity 1. Does anything in the product info explain the mismatch in price?

Hint 3 of 3 · Another clue

Compare the cart template’s line-item calculation with subtotal in cart.service.ts. After your change, test mixed sale and regular products and a promo code, then compare checkout with the saved order in My Orders. How could the shared subtotal use the same payable price as the line items while leaving the comparison price available for display?