# E2E test report (agent-friendly)

Plain-markdown digest of the Playwright e2e run, generated for AI agents. The interactive HTML report (screenshots, videos, traces) is served from this same deployment root.

- Commit: 01c4b13a94cc49364c38074f976a631cf2eaef77
- Workflow run: https://github.com/sanity-io/plugins/actions/runs/31091061176
- Summary: 39 passed, 1 failed, 0 flaky, 0 skipped

## ❌ firefox › media/media.spec.ts › sanity-plugin-media › auto-tags an asset when selected via mediaField

- Location: `tests/media/media.spec.ts:143:3`
- Browser (Playwright project): firefox
- Status: failed (3 attempts, all failed)

### Error (attempt 3 of 3)

```
Error: expect(received).toContain(expected) // indexOf

Expected value: "media.tag.a9baec88-a385-4983-ac8d-e59978187202"
Received array: ["NBTKJKq9Bc1c89OGfVoTFI"]

Call Log:
- Timeout 30000ms exceeded while waiting on the predicate
    at /home/runner/work/plugins/plugins/e2e/tests/media/media.spec.ts:165:10

  163 |       await expect
  164 |         .poll(async () => getMediaAssetTags(projectName, asset.id), {timeout: 30_000})
> 165 |         .toContain(tagId)
      |          ^
  166 |     } finally {
  167 |       await deleteMediaDocuments(projectName, cleanupIds)
  168 |     }
```

### Page snapshot at the moment of failure

# Instructions

- Following Playwright test failed.
- Explain why, be concise, respect Playwright best practices.
- Provide a snippet of code with the fix, if possible.

# Test info

- Name: media/media.spec.ts >> sanity-plugin-media >> auto-tags an asset when selected via mediaField
- Location: tests/media/media.spec.ts:143:3

# Error details

```
Error: expect(received).toContain(expected) // indexOf

Expected value: "media.tag.a9baec88-a385-4983-ac8d-e59978187202"
Received array: ["NBTKJKq9Bc1c89OGfVoTFI"]

Call Log:
- Timeout 30000ms exceeded while waiting on the predicate
```

# Page snapshot

```yaml
- generic [ref=e2]:
  - generic [ref=e3]:
    - generic [ref=e6]:
      - generic [ref=e7]:
        - generic [ref=e9]:
          - link [ref=e10] [cursor=pointer]:
            - /url: /firefox
            - img [ref=e15]: F
          - button "Firefox" [ref=e18]
        - button "Create new document" [ref=e31]
        - button "Open search" [ref=e39]
      - generic [ref=e48]:
        - generic [ref=e49]:
          - link "Structure" [ref=e50] [cursor=pointer]:
            - /url: /firefox/structure
          - link "Media" [ref=e57] [cursor=pointer]:
            - /url: /firefox/media
          - link "Releases" [ref=e64] [cursor=pointer]:
            - /url: /firefox/releases
        - button [disabled] [ref=e73]
      - generic [ref=e82]:
        - generic [ref=e83]:
          - link [ref=e84]:
            - /url: /firefox/releases
          - generic [ref=e91]: Drafts
          - button [ref=e97]
        - button [ref=e105]
        - button "Global presence" [ref=e113]
        - button "Help and resources" [ref=e121]
        - button [ref=e131]:
          - generic "e2e-robot-dev (Robot)" [ref=e133]: eR
    - generic [ref=e143]:
      - generic [ref=e145]:
        - generic [ref=e146]: Content
        - listbox "Content" [ref=e157]:
          - option [ref=e158]:
            - link "Translation metadata" [ref=e159] [cursor=pointer]:
              - /url: /firefox/structure/translation.metadata
          - option [ref=e175]:
            - link "Lesson" [ref=e176] [cursor=pointer]:
              - /url: /firefox/structure/lesson
          - option [ref=e192]:
            - link "I18n Post" [ref=e193] [cursor=pointer]:
              - /url: /firefox/structure/i18nPost
          - option [ref=e209]:
            - link "Media Tag" [ref=e210] [cursor=pointer]:
              - /url: /firefox/structure/media.tag
          - option [ref=e227]:
            - link "Media Folder" [ref=e228] [cursor=pointer]:
              - /url: /firefox/structure/media.folder
          - option [ref=e244]:
            - link "Media Product" [ref=e245] [cursor=pointer]:
              - /url: /firefox/structure/mediaProduct
          - option [ref=e261]:
            - link "Smoke test document" [ref=e262] [cursor=pointer]:
              - /url: /firefox/structure/smokeTestDocument
      - generic [ref=e280]:
        - generic [ref=e284]:
          - generic [ref=e285]: Media Product
          - generic [ref=e291]:
            - link "Media Product" [ref=e293] [cursor=pointer]:
              - /url: /firefox/intent/create/template=mediaProduct;type=mediaProduct/
            - button [ref=e301]
        - combobox "Search list" [expanded] [ref=e314]
        - listbox "Media Product" [ref=e319]:
          - option [ref=e320]:
            - link "Product 197d27ee Product 197d27ee" [ref=e321] [cursor=pointer]:
              - /url: /firefox/structure/mediaProduct;197d27ee-2945-48b4-8b51-77eaf7c7272f
              - generic [ref=e324]:
                - img "Product 197d27ee" [ref=e327]
                - generic [ref=e328]: Product 197d27ee
      - generic [ref=e340]:
        - generic [ref=e342]:
          - generic [ref=e344]:
            - button "Published" [disabled] [ref=e347] [cursor=pointer]
            - button "Draft" [ref=e360] [cursor=pointer]
          - generic [ref=e372]:
            - button [ref=e374]
            - button "Comments" [ref=e383]
            - button [ref=e392]
            - button "Enter focus mode (hide navigation)" [ref=e402]
            - link [ref=e411] [cursor=pointer]:
              - /url: /firefox/structure/mediaProduct
        - generic [ref=e422]:
          - generic [ref=e423]: Product 197d27ee
          - generic [ref=e437]:
            - generic [ref=e440]:
              - generic [ref=e441]: Media Product
              - heading "Product 197d27ee" [level=2] [ref=e445]
            - generic [ref=e447]:
              - generic [ref=e452]:
                - generic [ref=e453]:
                  - generic [ref=e454]: Name
                  - generic:
                    - generic:
                      - generic:
                        - button "Field actions"
                    - generic:
                      - generic:
                        - button "Add comment"
                - textbox "Name" [ref=e466]: Product 197d27ee
              - group [ref=e470]:
                - generic [ref=e471]:
                  - generic [ref=e472]: Image
                  - generic [ref=e478]:
                    - button "Field actions" [ref=e481]
                    - button "Add comment" [ref=e492]
                - generic [ref=e508]:
                  - img "Preview of uploaded image" [ref=e510]
                  - button "Open image options menu" [ref=e514]
              - group [ref=e526]:
                - generic [ref=e527]:
                  - generic [ref=e528]: Attachment
                  - generic:
                    - generic:
                      - generic:
                        - button "Field actions"
                    - generic:
                      - generic:
                        - button "Add comment"
                - generic [ref=e544]:
                  - generic [ref=e545]: Drag or paste file here
                  - generic [ref=e546]:
                    - generic [ref=e547]:
                      - generic [ref=e548]: Upload
                      - button "Upload" [ref=e560]
                    - button "Select" [ref=e561]
          - generic [ref=e580]:
            - button "e2e-robot-dev (Robot) Edited 29 sec. ago" [ref=e583]:
              - generic [ref=e585]:
                - generic "e2e-robot-dev (Robot)" [ref=e587]: eR
                - generic [ref=e594]: Edited 29 sec. ago
            - generic [ref=e597]:
              - button "Publish" [ref=e599]
              - button "Open document actions" [ref=e612]
  - list
```

# Test source

```ts
  65  | 
  66  |       await expect
  67  |         .poll(async () => getMediaAssetTitle(projectName, asset.id), {timeout: 30_000})
  68  |         .toBe(nextTitle)
  69  |     } finally {
  70  |       await deleteMediaAsset(projectName, asset.id)
  71  |     }
  72  |   })
  73  | 
  74  |   test('selects an image from the Media asset source into a document field', async ({
  75  |     page,
  76  |   }, testInfo) => {
  77  |     const projectName = testInfo.project.name
  78  |     const asset = await seedMediaImage(projectName)
  79  |     const doc = await seedMediaProduct(projectName)
  80  | 
  81  |     try {
  82  |       await openMediaProduct(page, doc.id)
  83  |       await openMediaAssetSource(page, 'Image')
  84  |       // mediaField pre-filters when a matching tag exists in the dataset (e.g. from
  85  |       // a parallel auto-tag run) — clear so the untagged seed is visible.
  86  |       await clearMediaSearchFacets(page)
  87  |       await searchMediaAssets(page, asset.filename)
  88  | 
  89  |       const card = mediaAssetCard(page, asset.id)
  90  |       await expect(card).toBeVisible({timeout: 30_000})
  91  |       await card.click()
  92  | 
  93  |       // Assert via the form UI — Content Lake draft visibility can lag / differ
  94  |       // under releases perspective, while the picker selection is already applied.
  95  |       await expect(selectedImagePreview(page)).toBeVisible({timeout: 30_000})
  96  |     } finally {
  97  |       await deleteMediaDocuments(projectName, [doc.id])
  98  |       await deleteMediaAsset(projectName, asset.id)
  99  |     }
  100 |   })
  101 | 
  102 |   test('uploads an image through the Media tool', async ({page}) => {
  103 |     await openMediaTool(page)
  104 |     const uploadedFilename = await uploadTinyPngViaMediaTool(page)
  105 | 
  106 |     await searchMediaAssets(page, uploadedFilename)
  107 |     await expect(page.getByText(uploadedFilename).first()).toBeVisible({timeout: 60_000})
  108 |   })
  109 | 
  110 |   test('creates a tag from the Tags panel', async ({page}) => {
  111 |     const tagName = `e2e-tag-${Date.now().toString(36)}`
  112 | 
  113 |     await openMediaTool(page)
  114 |     await openTagsPanel(page)
  115 | 
  116 |     await page.getByRole('button', {name: 'Create tag', exact: true}).click()
  117 |     const createDialog = page.getByRole('dialog', {name: /create tag/i})
  118 |     await expect(createDialog).toBeVisible()
  119 |     await createDialog.locator('input[name="name"]').fill(tagName)
  120 |     await createDialog.getByRole('button', {name: /save and close/i}).click()
  121 |     await expect(createDialog).toBeHidden({timeout: 30_000})
  122 |     await expect(page.getByText(tagName).first()).toBeVisible({timeout: 30_000})
  123 |   })
  124 | 
  125 |   test('filters assets by folder in the Media tool', async ({page}, testInfo) => {
  126 |     const projectName = testInfo.project.name
  127 |     const folderName = `E2E Folder ${Date.now()}`
  128 |     const folderId = await seedMediaFolder(projectName, folderName)
  129 |     const asset = await seedMediaImage(projectName, {folderId})
  130 |     const cleanupIds = [asset.id, folderId]
  131 | 
  132 |     try {
  133 |       await openMediaTool(page)
  134 |       await openFoldersPanel(page)
  135 |       await expect(page.getByText(folderName).first()).toBeVisible({timeout: 30_000})
  136 |       await page.getByText(folderName).first().click()
  137 |       await expect(mediaAssetCard(page, asset.id)).toBeVisible({timeout: 30_000})
  138 |     } finally {
  139 |       await deleteMediaDocuments(projectName, cleanupIds)
  140 |     }
  141 |   })
  142 | 
  143 |   test('auto-tags an asset when selected via mediaField', async ({page}, testInfo) => {
  144 |     const projectName = testInfo.project.name
  145 |     const tagId = await seedMediaTag(projectName, 'product')
  146 |     const asset = await seedMediaImage(projectName)
  147 |     const doc = await seedMediaProduct(projectName)
  148 |     const cleanupIds = [doc.id, asset.id, tagId]
  149 | 
  150 |     try {
  151 |       await openMediaProduct(page, doc.id)
  152 |       await openMediaAssetSource(page, 'Image')
  153 |       // mediaField pre-filters to the `product` tag — clear so the untagged seed is visible.
  154 |       await clearMediaSearchFacets(page)
  155 |       await searchMediaAssets(page, asset.filename)
  156 | 
  157 |       const card = mediaAssetCard(page, asset.id)
  158 |       await expect(card).toBeVisible({timeout: 30_000})
  159 |       await card.click()
  160 | 
  161 |       await expect(selectedImagePreview(page)).toBeVisible({timeout: 30_000})
  162 | 
  163 |       await expect
  164 |         .poll(async () => getMediaAssetTags(projectName, asset.id), {timeout: 30_000})
> 165 |         .toContain(tagId)
      |          ^ Error: expect(received).toContain(expected) // indexOf
  166 |     } finally {
  167 |       await deleteMediaDocuments(projectName, cleanupIds)
  168 |     }
  169 |   })
  170 | 
  171 |   test('edits asset metadata via Edit Media from a document field', async ({page}, testInfo) => {
  172 |     const projectName = testInfo.project.name
  173 |     const asset = await seedMediaImage(projectName, {title: 'Before edit'})
  174 |     const doc = await seedMediaProduct(projectName, {imageAssetId: asset.id})
  175 |     const nextTitle = `Edited via form ${asset.id.slice(-6)}`
  176 |     const cleanupIds = [doc.id, asset.id]
  177 | 
  178 |     try {
  179 |       await openMediaProduct(page, doc.id)
  180 |       await openEditMediaSource(page, 'Image')
  181 | 
  182 |       const dialog = assetDetailsDialog(page)
  183 |       const titleInput = dialog.locator('input[name="title"]')
  184 |       await expect(titleInput).toBeVisible()
  185 |       await titleInput.fill(nextTitle)
  186 |       // Under React Strict Mode, a duplicate dialog layer can intercept clicks.
  187 |       await dialog.getByRole('button', {name: /save and close/i}).click({force: true})
  188 | 
  189 |       await expect
  190 |         .poll(async () => getMediaAssetTitle(projectName, asset.id), {timeout: 30_000})
  191 |         .toBe(nextTitle)
  192 | 
  193 |       // Best-effort dismiss of any leftover dialog layers from Strict Mode.
  194 |       await page.keyboard.press('Escape').catch(() => undefined)
  195 |     } finally {
  196 |       await deleteMediaDocuments(projectName, cleanupIds)
  197 |     }
  198 |   })
  199 | })
  200 | 
```

### Other attachments (available in the HTML report at this deployment root)

- video (video/webm)


## How to reproduce locally

From the repository root:

```sh
SANITY_E2E_PROJECT_ID=a1psl692 \
SANITY_E2E_BASE_URL=https://plugins-e2e-test-studio-rjfh7t67c.sanity.dev \
SANITY_E2E_DATASET_CHROMIUM=pr-1851-chromium-31091061176 \
SANITY_E2E_DATASET_FIREFOX=pr-1851-firefox-31091061176 \
pnpm test:e2e \
  tests/media/media.spec.ts
```
