| 1 | import { describe, expect, it } from "vite-plus/test"; |
| 2 | |
| 3 | import { |
| 4 | beginProjectFaviconRequest, |
| 5 | createProjectFaviconRequest, |
| 6 | hasLoadedProjectFavicon, |
| 7 | markProjectFaviconFailed, |
| 8 | markProjectFaviconLoaded, |
| 9 | } from "./projectFaviconRequests"; |
| 10 | |
| 11 | describe("project favicon requests", () => { |
| 12 | it("ignores callbacks from a superseded URL", () => { |
| 13 | const cacheKey = "environment-1:/workspace:v1-favicon.svg"; |
| 14 | const expiredUrl = "https://environment.example/api/assets/expired/v1-favicon.svg"; |
| 15 | const refreshedUrl = "https://environment.example/api/assets/refreshed/v1-favicon.svg"; |
| 16 | |
| 17 | const expiredRequest = createProjectFaviconRequest(cacheKey, expiredUrl); |
| 18 | const endExpiredRequest = beginProjectFaviconRequest(expiredRequest); |
| 19 | markProjectFaviconLoaded(expiredRequest); |
| 20 | const refreshedRequest = createProjectFaviconRequest(cacheKey, refreshedUrl); |
| 21 | const endRefreshedRequest = beginProjectFaviconRequest(refreshedRequest); |
| 22 | |
| 23 | expect(markProjectFaviconLoaded(expiredRequest)).toBe(false); |
| 24 | expect(markProjectFaviconFailed(expiredRequest)).toBe(false); |
| 25 | expect(hasLoadedProjectFavicon(cacheKey)).toBe(true); |
| 26 | expect(markProjectFaviconFailed(refreshedRequest)).toBe(true); |
| 27 | expect(hasLoadedProjectFavicon(cacheKey)).toBe(false); |
| 28 | |
| 29 | endRefreshedRequest(); |
| 30 | endExpiredRequest(); |
| 31 | }); |
| 32 | |
| 33 | it("evicts the URL that actually failed", () => { |
| 34 | const cacheKey = "environment-1:/workspace:v2-favicon.svg"; |
| 35 | const faviconUrl = "https://environment.example/api/assets/current/v2-favicon.svg"; |
| 36 | const request = createProjectFaviconRequest(cacheKey, faviconUrl); |
| 37 | const endRequest = beginProjectFaviconRequest(request); |
| 38 | |
| 39 | markProjectFaviconLoaded(request); |
| 40 | |
| 41 | expect(markProjectFaviconFailed(request)).toBe(true); |
| 42 | expect(hasLoadedProjectFavicon(cacheKey)).toBe(false); |
| 43 | |
| 44 | endRequest(); |
| 45 | }); |
| 46 | |
| 47 | it("does not supersede a request until the next request begins", () => { |
| 48 | const cacheKey = "environment-1:/workspace:v3-favicon.svg"; |
| 49 | const committedUrl = "https://environment.example/api/assets/current/v3-favicon.svg"; |
| 50 | const abandonedUrl = "https://environment.example/api/assets/abandoned/v3-favicon.svg"; |
| 51 | const committedRequest = createProjectFaviconRequest(cacheKey, committedUrl); |
| 52 | const endCommittedRequest = beginProjectFaviconRequest(committedRequest); |
| 53 | |
| 54 | createProjectFaviconRequest(cacheKey, abandonedUrl); |
| 55 | |
| 56 | expect(markProjectFaviconLoaded(committedRequest)).toBe(true); |
| 57 | expect(hasLoadedProjectFavicon(cacheKey)).toBe(true); |
| 58 | |
| 59 | endCommittedRequest(); |
| 60 | }); |
| 61 | |
| 62 | it("requires a cache key before creating a URL-bearing request", () => { |
| 63 | const firstUrl = "https://environment.example/api/assets/first/favicon.svg"; |
| 64 | const secondUrl = "https://environment.example/api/assets/second/favicon.svg"; |
| 65 | |
| 66 | expect(createProjectFaviconRequest(null, firstUrl)).toBeNull(); |
| 67 | expect(createProjectFaviconRequest(null, secondUrl)).toBeNull(); |
| 68 | }); |
| 69 | |
| 70 | it("restores the remaining active URL when a newer request ends", () => { |
| 71 | const cacheKey = "environment-1:/workspace:v4-favicon.svg"; |
| 72 | const firstRequest = createProjectFaviconRequest( |
| 73 | cacheKey, |
| 74 | "https://environment.example/api/assets/first/v4-favicon.svg", |
| 75 | ); |
| 76 | const secondRequest = createProjectFaviconRequest( |
| 77 | cacheKey, |
| 78 | "https://environment.example/api/assets/second/v4-favicon.svg", |
| 79 | ); |
| 80 | const endFirstRequest = beginProjectFaviconRequest(firstRequest); |
| 81 | const endSecondRequest = beginProjectFaviconRequest(secondRequest); |
| 82 | |
| 83 | expect(markProjectFaviconLoaded(firstRequest)).toBe(false); |
| 84 | endSecondRequest(); |
| 85 | expect(markProjectFaviconLoaded(firstRequest)).toBe(true); |
| 86 | endFirstRequest(); |
| 87 | expect(markProjectFaviconLoaded(firstRequest)).toBe(false); |
| 88 | }); |
| 89 | |
| 90 | it("bounds remembered loaded revisions", () => { |
| 91 | const firstCacheKey = "environment-1:/workspace:revision-0"; |
| 92 | let lastCacheKey = firstCacheKey; |
| 93 | |
| 94 | for (let revision = 0; revision < 300; revision++) { |
| 95 | lastCacheKey = `environment-1:/workspace:revision-${revision}`; |
| 96 | const request = createProjectFaviconRequest( |
| 97 | lastCacheKey, |
| 98 | `https://environment.example/api/assets/revision-${revision}/favicon.svg`, |
| 99 | ); |
| 100 | const endRequest = beginProjectFaviconRequest(request); |
| 101 | markProjectFaviconLoaded(request); |
| 102 | endRequest(); |
| 103 | } |
| 104 | |
| 105 | expect(hasLoadedProjectFavicon(firstCacheKey)).toBe(false); |
| 106 | expect(hasLoadedProjectFavicon(lastCacheKey)).toBe(true); |
| 107 | }); |
| 108 | }); |