question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[BUG] Timeout of 30000ms exceeded while running fixture "browser" setup. (using Firefox)

See original GitHub issue

Context:

  • Playwright Version: 1.22
  • Operating System: Ubuntu
  • Node.js version: v16.15.0
  • Browser: Firefox
  • Extra: Run using TeamCity, on a Linux VM with a Docker TeamCity build agent and the Playwright Docker container

Code Snippet

Help us help you! Put down a short code snippet that illustrates your bug and that we can run and debug locally. For example:

import { test, expect, Page } from '@playwright/test';

test.beforeEach(async ({ page }) => {
  await page.goto('https://demo.playwright.dev/todomvc');
});

const TODO_ITEMS = [
  'buy some cheese',
  'feed the cat',
  'book a doctors appointment'
];

test.describe('New Todo', () => {
  test('should allow me to add todo items', async ({ page }) => {
    // Create 1st todo.
    await page.locator('.new-todo').fill(TODO_ITEMS[0]);
    await page.locator('.new-todo').press('Enter');

    // Make sure the list only has one todo item.
    await expect(page.locator('.view label')).toHaveText([
      TODO_ITEMS[0]
    ]);

    // Create 2nd todo.
    await page.locator('.new-todo').fill(TODO_ITEMS[1]);
    await page.locator('.new-todo').press('Enter');

    // Make sure the list now has two todo items.
    await expect(page.locator('.view label')).toHaveText([
      TODO_ITEMS[0],
      TODO_ITEMS[1]
    ]);

    await checkNumberOfTodosInLocalStorage(page, 2);
  });

  test('should clear text input field when an item is added', async ({ page }) => {
    // Create one todo item.
    await page.locator('.new-todo').fill(TODO_ITEMS[0]);
    await page.locator('.new-todo').press('Enter');

    // Check that input is empty.
    await expect(page.locator('.new-todo')).toBeEmpty();
    await checkNumberOfTodosInLocalStorage(page, 1);
  });

  test('should append new items to the bottom of the list', async ({ page }) => {
    // Create 3 items.
    await createDefaultTodos(page);

    // Check test using different methods.
    await expect(page.locator('.todo-count')).toHaveText('3 items left');
    await expect(page.locator('.todo-count')).toContainText('3');
    await expect(page.locator('.todo-count')).toHaveText(/3/);

    // Check all items in one call.
    await expect(page.locator('.view label')).toHaveText(TODO_ITEMS);
    await checkNumberOfTodosInLocalStorage(page, 3);
  });

  test('should show #main and #footer when items added', async ({ page }) => {
    await page.locator('.new-todo').fill(TODO_ITEMS[0]);
    await page.locator('.new-todo').press('Enter');

    await expect(page.locator('.main')).toBeVisible();
    await expect(page.locator('.footer')).toBeVisible();
    await checkNumberOfTodosInLocalStorage(page, 1);
  });
});

test.describe('Mark all as completed', () => {
  test.beforeEach(async ({ page }) => {
    await createDefaultTodos(page);
    await checkNumberOfTodosInLocalStorage(page, 3);
  });

  test.afterEach(async ({ page }) => {
    await checkNumberOfTodosInLocalStorage(page, 3);
  });

  test('should allow me to mark all items as completed', async ({ page }) => {
    // Complete all todos.
    await page.locator('.toggle-all').check();

    // Ensure all todos have 'completed' class.
    await expect(page.locator('.todo-list li')).toHaveClass(['completed', 'completed', 'completed']);
    await checkNumberOfCompletedTodosInLocalStorage(page, 3);
  });

  test('should allow me to clear the complete state of all items', async ({ page }) => {
    // Check and then immediately uncheck.
    await page.locator('.toggle-all').check();
    await page.locator('.toggle-all').uncheck();

    // Should be no completed classes.
    await expect(page.locator('.todo-list li')).toHaveClass(['', '', '']);
  });

  test('complete all checkbox should update state when items are completed / cleared', async ({ page }) => {
    const toggleAll = page.locator('.toggle-all');
    await toggleAll.check();
    await expect(toggleAll).toBeChecked();
    await checkNumberOfCompletedTodosInLocalStorage(page, 3);

    // Uncheck first todo.
    const firstTodo = page.locator('.todo-list li').nth(0);
    await firstTodo.locator('.toggle').uncheck();

    // Reuse toggleAll locator and make sure its not checked.
    await expect(toggleAll).not.toBeChecked();

    await firstTodo.locator('.toggle').check();
    await checkNumberOfCompletedTodosInLocalStorage(page, 3);

    // Assert the toggle all is checked again.
    await expect(toggleAll).toBeChecked();
  });
});

test.describe('Item', () => {

  test('should allow me to mark items as complete', async ({ page }) => {
    // Create two items.
    for (const item of TODO_ITEMS.slice(0, 2)) {
      await page.locator('.new-todo').fill(item);
      await page.locator('.new-todo').press('Enter');
    }

    // Check first item.
    const firstTodo = page.locator('.todo-list li').nth(0);
    await firstTodo.locator('.toggle').check();
    await expect(firstTodo).toHaveClass('completed');

    // Check second item.
    const secondTodo = page.locator('.todo-list li').nth(1);
    await expect(secondTodo).not.toHaveClass('completed');
    await secondTodo.locator('.toggle').check();

    // Assert completed class.
    await expect(firstTodo).toHaveClass('completed');
    await expect(secondTodo).toHaveClass('completed');
  });

  test('should allow me to un-mark items as complete', async ({ page }) => {
    // Create two items.
    for (const item of TODO_ITEMS.slice(0, 2)) {
      await page.locator('.new-todo').fill(item);
      await page.locator('.new-todo').press('Enter');
    }

    const firstTodo = page.locator('.todo-list li').nth(0);
    const secondTodo = page.locator('.todo-list li').nth(1);
    await firstTodo.locator('.toggle').check();
    await expect(firstTodo).toHaveClass('completed');
    await expect(secondTodo).not.toHaveClass('completed');
    await checkNumberOfCompletedTodosInLocalStorage(page, 1);

    await firstTodo.locator('.toggle').uncheck();
    await expect(firstTodo).not.toHaveClass('completed');
    await expect(secondTodo).not.toHaveClass('completed');
    await checkNumberOfCompletedTodosInLocalStorage(page, 0);
  });

  test('should allow me to edit an item', async ({ page }) => {
    await createDefaultTodos(page);

    const todoItems = page.locator('.todo-list li');
    const secondTodo = todoItems.nth(1);
    await secondTodo.dblclick();
    await expect(secondTodo.locator('.edit')).toHaveValue(TODO_ITEMS[1]);
    await secondTodo.locator('.edit').fill('buy some sausages');
    await secondTodo.locator('.edit').press('Enter');

    // Explicitly assert the new text value.
    await expect(todoItems).toHaveText([
      TODO_ITEMS[0],
      'buy some sausages',
      TODO_ITEMS[2]
    ]);
    await checkTodosInLocalStorage(page, 'buy some sausages');
  });
});

test.describe('Editing', () => {
  test.beforeEach(async ({ page }) => {
    await createDefaultTodos(page);
    await checkNumberOfTodosInLocalStorage(page, 3);
  });

  test('should hide other controls when editing', async ({ page }) => {
    const todoItem = page.locator('.todo-list li').nth(1);
    await todoItem.dblclick();
    await expect(todoItem.locator('.toggle')).not.toBeVisible();
    await expect(todoItem.locator('label')).not.toBeVisible();
    await checkNumberOfTodosInLocalStorage(page, 3);
  });

  test('should save edits on blur', async ({ page }) => {
    const todoItems = page.locator('.todo-list li');
    await todoItems.nth(1).dblclick();
    await todoItems.nth(1).locator('.edit').fill('buy some sausages');
    await todoItems.nth(1).locator('.edit').dispatchEvent('blur');

    await expect(todoItems).toHaveText([
      TODO_ITEMS[0],
      'buy some sausages',
      TODO_ITEMS[2],
    ]);
    await checkTodosInLocalStorage(page, 'buy some sausages');
  });

  test('should trim entered text', async ({ page }) => {
    const todoItems = page.locator('.todo-list li');
    await todoItems.nth(1).dblclick();
    await todoItems.nth(1).locator('.edit').fill('    buy some sausages    ');
    await todoItems.nth(1).locator('.edit').press('Enter');

    await expect(todoItems).toHaveText([
      TODO_ITEMS[0],
      'buy some sausages',
      TODO_ITEMS[2],
    ]);
    await checkTodosInLocalStorage(page, 'buy some sausages');
  });

  test('should remove the item if an empty text string was entered', async ({ page }) => {
    const todoItems = page.locator('.todo-list li');
    await todoItems.nth(1).dblclick();
    await todoItems.nth(1).locator('.edit').fill('');
    await todoItems.nth(1).locator('.edit').press('Enter');

    await expect(todoItems).toHaveText([
      TODO_ITEMS[0],
      TODO_ITEMS[2],
    ]);
  });

  test('should cancel edits on escape', async ({ page }) => {
    const todoItems = page.locator('.todo-list li');
    await todoItems.nth(1).dblclick();
    await todoItems.nth(1).locator('.edit').press('Escape');
    await expect(todoItems).toHaveText(TODO_ITEMS);
  });
});

test.describe('Counter', () => {
  test('should display the current number of todo items', async ({ page }) => {
    await page.locator('.new-todo').fill(TODO_ITEMS[0]);
    await page.locator('.new-todo').press('Enter');
    await expect(page.locator('.todo-count')).toContainText('1');

    await page.locator('.new-todo').fill(TODO_ITEMS[1]);
    await page.locator('.new-todo').press('Enter');
    await expect(page.locator('.todo-count')).toContainText('2');

    await checkNumberOfTodosInLocalStorage(page, 2);
  });
});

test.describe('Clear completed button', () => {
  test.beforeEach(async ({ page }) => {
    await createDefaultTodos(page);
  });

  test('should display the correct text', async ({ page }) => {
    await page.locator('.todo-list li .toggle').first().check();
    await expect(page.locator('.clear-completed')).toHaveText('Clear completed');
  });

  test('should remove completed items when clicked', async ({ page }) => {
    const todoItems = page.locator('.todo-list li');
    await todoItems.nth(1).locator('.toggle').check();
    await page.locator('.clear-completed').click();
    await expect(todoItems).toHaveCount(2);
    await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]);
  });

  test('should be hidden when there are no items that are completed', async ({ page }) => {
    await page.locator('.todo-list li .toggle').first().check();
    await page.locator('.clear-completed').click();
    await expect(page.locator('.clear-completed')).toBeHidden();
  });
});

test.describe('Persistence', () => {
  test('should persist its data', async ({ page }) => {
    for (const item of TODO_ITEMS.slice(0, 2)) {
      await page.locator('.new-todo').fill(item);
      await page.locator('.new-todo').press('Enter');
    }

    const todoItems = page.locator('.todo-list li');
    await todoItems.nth(0).locator('.toggle').check();
    await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]);
    await expect(todoItems).toHaveClass(['completed', '']);

    // Ensure there is 1 completed item.
    checkNumberOfCompletedTodosInLocalStorage(page, 1);

    // Now reload.
    await page.reload();
    await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]);
    await expect(todoItems).toHaveClass(['completed', '']);
  });
});

test.describe('Routing', () => {
  test.beforeEach(async ({ page }) => {
    await createDefaultTodos(page);
    // make sure the app had a chance to save updated todos in storage
    // before navigating to a new view, otherwise the items can get lost :(
    // in some frameworks like Durandal
    await checkTodosInLocalStorage(page, TODO_ITEMS[0]);
  });

  test('should allow me to display active items', async ({ page }) => {
    await page.locator('.todo-list li .toggle').nth(1).check();
    await checkNumberOfCompletedTodosInLocalStorage(page, 1);
    await page.locator('.filters >> text=Active').click();
    await expect(page.locator('.todo-list li')).toHaveCount(2);
    await expect(page.locator('.todo-list li')).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]);
  });

  test('should respect the back button', async ({ page }) => {
    await page.locator('.todo-list li .toggle').nth(1).check();
    await checkNumberOfCompletedTodosInLocalStorage(page, 1);

    await test.step('Showing all items', async () => {
      await page.locator('.filters >> text=All').click();
      await expect(page.locator('.todo-list li')).toHaveCount(3);
    });

    await test.step('Showing active items', async () => {
      await page.locator('.filters >> text=Active').click();
    });

    await test.step('Showing completed items', async () => {
      await page.locator('.filters >> text=Completed').click();
    });

    await expect(page.locator('.todo-list li')).toHaveCount(1);
    await page.goBack();
    await expect(page.locator('.todo-list li')).toHaveCount(2);
    await page.goBack();
    await expect(page.locator('.todo-list li')).toHaveCount(3);
  });

  test('should allow me to display completed items', async ({ page }) => {
    await page.locator('.todo-list li .toggle').nth(1).check();
    await checkNumberOfCompletedTodosInLocalStorage(page, 1);
    await page.locator('.filters >> text=Completed').click();
    await expect(page.locator('.todo-list li')).toHaveCount(1);
  });

  test('should allow me to display all items', async ({ page }) => {
    await page.locator('.todo-list li .toggle').nth(1).check();
    await checkNumberOfCompletedTodosInLocalStorage(page, 1);
    await page.locator('.filters >> text=Active').click();
    await page.locator('.filters >> text=Completed').click();
    await page.locator('.filters >> text=All').click();
    await expect(page.locator('.todo-list li')).toHaveCount(3);
  });

  test('should highlight the currently applied filter', async ({ page }) => {
    await expect(page.locator('.filters >> text=All')).toHaveClass('selected');
    await page.locator('.filters >> text=Active').click();
    // Page change - active items.
    await expect(page.locator('.filters >> text=Active')).toHaveClass('selected');
    await page.locator('.filters >> text=Completed').click();
    // Page change - completed items.
    await expect(page.locator('.filters >> text=Completed')).toHaveClass('selected');
  });
});

async function createDefaultTodos(page: Page) {
  for (const item of TODO_ITEMS) {
    await page.locator('.new-todo').fill(item);
    await page.locator('.new-todo').press('Enter');
  }
}

async function checkNumberOfTodosInLocalStorage(page: Page, expected: number) {
  return await page.waitForFunction(e => {
    return JSON.parse(localStorage['react-todos']).length === e;
  }, expected);
}

async function checkNumberOfCompletedTodosInLocalStorage(page: Page, expected: number) {
  return await page.waitForFunction(e => {
    return JSON.parse(localStorage['react-todos']).filter((todo: any) => todo.completed).length === e;
  }, expected);
}

async function checkTodosInLocalStorage(page: Page, title: string) {
  return await page.waitForFunction(t => {
    return JSON.parse(localStorage['react-todos']).map((todo: any) => todo.title).includes(t);
  }, title);
}

Describe the bug

I have other code I am using for this, but I was able to reproduce the issue with the default example tests provided here that Playwright provides when downloading it. I am running my tests on TeamCity. I have a Linux VM with a TeamCity build agent Docker container. I am also using the Docker container from Playwright to run the tests in. So far, the tests run fine in Chromium and Safari. However, I get the following error when trying to run them in Firefox: Timeout of 30000ms exceeded while running fixture “browser” setup. at /opt/buildagent/work/6f7a18f2c8f56a5c/PolicyTechAutomationTests/tests/smoketestshould.spec.ts:94:6 That line in my code (which is different than the code pasted here) is: test.beforeAll(async ({ browser }) => { I am able to run these tests using Firefox on my local environment without issue. It is almost as if the Playwright Docker container is acting like Firefox does not exist.

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:36 (8 by maintainers)

github_iconTop GitHub Comments

3reactions
KenjiTakahashicommented, Jun 3, 2022

@aslushnikov Installing from inside the container does not fix the issue for me. I did some further experiments. Using the same example project code from npm init, but removed node_modules and package*json.

docker run --rm -it -v $(pwd):/code/t/ mcr.microsoft.com/playwright:v1.22.2-focal /bin/bash

Then inside the container:

  1. cd /code/
  2. npm i @playwright/test
  3. npx playwright test -c /code/t/playwright.config.ts --project firefox -> This works fine.
  4. cd /t/
  5. npx playwright test -c /code/t/playwright.config.ts --project firefox -> This fails.

Then I did the “opposite” (in new container):

  1. cd /code/t/
  2. npm i @playwright/test
  3. npx --prefix /code/t/ playwright test -c /code/t/playwright.config.ts --project firefox -> This fails.
  4. cd ..
  5. npx --prefix /code/t/ playwright test -c /code/t/playwright.config.ts --project firefox -> This works.

So it looks like the trigger is cwd being on a bind mount. Doesn’t matter if the code or deps are also bind mounted or not. But why that is, I can’t really tell. And why it only fails for Firefox? Sth wrong with how Firefox handles files in bind mounted dirs?

2reactions
jkiladacommented, Jun 3, 2022

Thanks @KenjiTakahashi for your research. I was able to resolve the issue in a similar manner by ensuring cwd was outside of the bind mount before invoking the tests.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Webscraping TimeoutError: Navigation timeout of 30000 ms ...
there's an SSL error (e.g. in case of self-signed certificates). target URL is invalid. the timeout is exceeded during navigation. the remote ...
Read more >
playwright._impl._api_types.timeouterror: timeout 30000ms ...
TimeoutError : Timeout 30000ms exceeded. ... Firefox browser can be opened smoothly,but he reported an error. I can't find the reason please help ......
Read more >
Changelog - Cypress Documentation
In Cypress 12, we enforce running tests in a clean browser context through ... The Spec Runner will no longer overflow unexpectedly in...
Read more >
Run your first Playwright test on BrowserStack Automate
A quickstart guide to running your first Playwright test across 100+ desktop browsers on BrowserStack.
Read more >
How can I adjust the Timeout setting? | Firefox Support Forum
I'm running some OBIEE reports in Firefox that by nature do take a long time to run. One of my local Tech Support...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found