~cytrogen/gstack

ref: cd66fc2f890982351e3178925be563681d0ab2c5 gstack/browse/test/fixtures/qa-eval-spa.html -rw-r--r-- 3.2 KiB
cd66fc2f — Garry Tan fix: 6 critical fixes + community PR guardrails (v0.13.2.0) (#602) 13 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>QA Eval — SPA Store</title>
  <style>
    body { font-family: sans-serif; padding: 20px; margin: 0; }
    nav { background: #333; padding: 10px 20px; }
    nav a { color: white; margin-right: 15px; text-decoration: none; cursor: pointer; }
    nav a:hover { text-decoration: underline; }
    #app { padding: 20px; }
    .product { border: 1px solid #ddd; padding: 10px; margin: 10px 0; border-radius: 4px; }
    .product button { padding: 6px 12px; background: #0066cc; color: white; border: none; cursor: pointer; }
    .cart-count { background: #cc0000; color: white; padding: 2px 8px; border-radius: 10px; font-size: 12px; }
    .error { color: red; padding: 10px; }
    .loading { color: #666; padding: 10px; }
  </style>
</head>
<body>
  <nav>
    <a href="#/home">Home</a>
    <a href="#/prodcts">Products</a>  <!-- BUG 1: broken route — typo "prodcts" instead of "products" -->
    <a href="#/contact">Contact</a>
    <span class="cart-count" id="cart-count">0</span>
  </nav>

  <div id="app">
    <p>Welcome to SPA Store. Use the navigation above.</p>
  </div>

  <script>
    let cartCount = 0;

    // BUG 2: cart count never resets on route change — stale state
    function addToCart() {
      cartCount++;
      document.getElementById('cart-count').textContent = cartCount;
    }

    function renderHome() {
      document.getElementById('app').innerHTML = `
        <h1>Welcome to SPA Store</h1>
        <p>Browse our products using the navigation above.</p>
      `;
    }

    function renderProducts() {
      document.getElementById('app').innerHTML = '<p class="loading">Loading products...</p>';

      // BUG 3: async race — shows data briefly, then shows error
      setTimeout(() => {
        document.getElementById('app').innerHTML = `
          <h1>Products</h1>
          <div class="product">
            <h3>Widget A</h3>
            <p>$29.99</p>
            <button onclick="addToCart()">Add to Cart</button>
          </div>
          <div class="product">
            <h3>Widget B</h3>
            <p>$49.99</p>
            <button onclick="addToCart()">Add to Cart</button>
          </div>
        `;
      }, 300);

      setTimeout(() => {
        document.getElementById('app').innerHTML = '<p class="error">Error: Failed to fetch products from API</p>';
      }, 1000);
    }

    function renderContact() {
      document.getElementById('app').innerHTML = `
        <h1>Contact Us</h1>
        <p>Email: support@spastore.example.com</p>
      `;
    }

    // BUG 4: nav links have no aria-current attribute on active route
    function router() {
      const hash = window.location.hash || '#/home';
      switch (hash) {
        case '#/home': renderHome(); break;
        case '#/products': renderProducts(); break;
        case '#/contact': renderContact(); break;
        default:
          document.getElementById('app').innerHTML = '<p>Page not found</p>';
      }

      // BUG 5: console.warn on every route change — simulates listener leak
      console.warn('Possible memory leak detected: 11 event listeners added to window');
    }

    window.addEventListener('hashchange', router);
    router();
  </script>
</body>
</html>