{"id":76679,"date":"2025-10-18T12:35:03","date_gmt":"2025-10-18T07:05:03","guid":{"rendered":"https:\/\/www.tothenew.com\/blog\/?p=76679"},"modified":"2025-10-29T19:55:32","modified_gmt":"2025-10-29T14:25:32","slug":"how-session-storage-work-in-playwright","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/how-session-storage-work-in-playwright\/","title":{"rendered":"How Session Storage Work in Playwright"},"content":{"rendered":"<p>In Automation Testing logging into an application repeatedly for every test case can be time-consuming and inefficient as well. To rescue with this problem Session Storage state comes to picture with narrative of &#8220;<strong>Modern Day Problems Require Modern Day Solution<\/strong>&#8221;<\/p>\n<p>By saving the authenticated state once and reusing it across multiple tests, automation engineer can skip redundant login steps and focus on only business flows.<\/p>\n<p>In this post we will dive deep what is session storage, how it helpful in automation framework, how, where and when you implement session storage, troubleshooting problem and their solution, best practice to secure session storage, pros and cons of it, and real-world test automation code to store session<\/p>\n<p>Below are the points which we are cover in this post<\/p>\n<ul>\n<li>What is session storage?<\/li>\n<li>Why reuse session in automation framework?<\/li>\n<li>How session usability work in Playwright?<\/li>\n<li>Internal flow behind the scenes<\/li>\n<li>When should you use when not?<\/li>\n<li>Troubleshooting common issues<\/li>\n<li>Best practices<\/li>\n<li>Pros and Cons<\/li>\n<li>Setting up global setup for session storage in playwright<\/li>\n<\/ul>\n<h2>What is Session Storage?<\/h2>\n<ul>\n<li>When you log in to any website, your login details (like token, session IDs and Cookies) are temporarily stored in the browser, which is called <strong>session storage.<\/strong><\/li>\n<li>It helps the browser remember that you are already logged in, so you don&#8217;t have to re-enter your credentials (username\/email and password) again and again while dealing with multiple test case scenario.<\/li>\n<li>But here is a catch, once you close the browser this session data is gone<\/li>\n<\/ul>\n<h2>Why Reuse Session in Automation Framework?<\/h2>\n<ul>\n<li>In Automation testing, every test case starts in incognito mode, which open the fresh browser every time, you&#8217;ll end up logging in again and again every single time which is not efficient and profitable too to do the same things again and again<\/li>\n<li>To overcome with above issue <strong>session re-usability<\/strong> comes into the picture which helps us to <strong>login once and test everything<\/strong><\/li>\n<\/ul>\n<h2>How Session Usability Works in Playwright?<\/h2>\n<ul>\n<li>Playwright stores all cookies, <strong>localStorage, and sessionStorage data\u00a0<\/strong>from your logged-in browser context into a file (like <span style=\"color: #008000;\">storageState.json<\/span>)<\/li>\n<li>During test execution, Playwright reads that file and <strong>restores the browser state exactly as it was<\/strong> after login.<\/li>\n<li>This means the app is recognizes the user as already logged in, no login state and delay user direct navigate to the home\/dashboard page <strong>bypassing login state<\/strong><\/li>\n<li>Think of it like taking snapshot of your logged-in browser and reusing the snapshot every time your test run\n<div id=\"attachment_76677\" style=\"width: 223px\" class=\"wp-caption alignnone\"><img aria-describedby=\"caption-attachment-76677\" decoding=\"async\" loading=\"lazy\" class=\"size-medium wp-image-76677\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2025\/10\/storageStateFile-213x300.png\" alt=\"storageState\" width=\"213\" height=\"300\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2025\/10\/storageStateFile-213x300.png 213w, \/blog\/wp-ttn-blog\/uploads\/2025\/10\/storageStateFile.png 343w\" sizes=\"(max-width: 213px) 100vw, 213px\" \/><p id=\"caption-attachment-76677\" class=\"wp-caption-text\">sample session storage state template<\/p><\/div>\n<p>&nbsp;<\/li>\n<\/ul>\n<h2>Internal Flow Behind The Scenes<\/h2>\n<ul>\n<li><strong>Global Setup Phase (before test run)<\/strong>\n<ol style=\"list-style-type: lower-roman;\">\n<li>Browser launches<\/li>\n<li>Login happens once<\/li>\n<li>Session Saved<\/li>\n<li>Browser Closed<\/li>\n<\/ol>\n<\/li>\n<li><strong>Test Execution Phase<\/strong>\n<ul>\n<li>Each test picks up the saved session file (<span style=\"color: #008000;\">storageState.json<\/span>) and starts from logged in state by passing login state<\/li>\n<\/ul>\n<\/li>\n<li><strong>Result<\/strong>\n<ul>\n<li>Test directly land on the protected route (like \/dashboard, home\/, \/profile and etc.) without re-login<\/li>\n<\/ul>\n<\/li>\n<li>Flow Diagram<\/li>\n<\/ul>\n<div id=\"attachment_76678\" style=\"width: 310px\" class=\"wp-caption alignnone\"><img aria-describedby=\"caption-attachment-76678\" decoding=\"async\" loading=\"lazy\" class=\"size-medium wp-image-76678\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2025\/10\/sessionStorageFlow-300x200.png\" alt=\"StorageFlow\" width=\"300\" height=\"200\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2025\/10\/sessionStorageFlow-300x200.png 300w, \/blog\/wp-ttn-blog\/uploads\/2025\/10\/sessionStorageFlow-1024x683.png 1024w, \/blog\/wp-ttn-blog\/uploads\/2025\/10\/sessionStorageFlow-768x512.png 768w, \/blog\/wp-ttn-blog\/uploads\/2025\/10\/sessionStorageFlow-624x416.png 624w, \/blog\/wp-ttn-blog\/uploads\/2025\/10\/sessionStorageFlow.png 1536w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><p id=\"caption-attachment-76678\" class=\"wp-caption-text\">Sesson Storage Flow<\/p><\/div>\n<h2>When Should You Use When Not?<\/h2>\n<ul>\n<li><strong>Do When<\/strong>\n<ul>\n<li>You have <strong>stable login flow<\/strong> that doesn&#8217;t change frequently<\/li>\n<li>Your webapp uses <strong>session or token-based authentication<\/strong> (like JWT)<\/li>\n<li>You want to <strong>save execution time<\/strong> and skip repetitive login steps<\/li>\n<li>You are working with <strong>large test suit<\/strong> (8+ spec file)<\/li>\n<\/ul>\n<\/li>\n<li><strong>Don&#8217;t When<\/strong>\n<ul>\n<li>You are testing login functionality itself (you need a fresh session)<\/li>\n<li>The session expires very quickly (every 2-3 minutes)<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2>Troubleshooting Common Issues<\/h2>\n<p>Here are a few things Automation Engineer usually face while implementing session reusability<\/p>\n<ol>\n<li>\n<h3>&#8220;Session not valid&#8221; or &#8220;User not logged in&#8221;<\/h3>\n<ul style=\"list-style-type: disc;\">\n<li>The store session may have expired<\/li>\n<li>Solution: Re-run your global-setup file to generate a fresh <span style=\"color: #008000;\">storageState.json<\/span> file<\/li>\n<\/ul>\n<\/li>\n<li>\n<h3>&#8220;Cannot read storageState.json&#8221;<\/h3>\n<ul style=\"list-style-type: disc;\">\n<li>Path mismatch or wrong directory structure.<\/li>\n<li>Solution: Use <span style=\"color: #008000;\">path.resolve(__dirname, &#8216;storageState.json&#8217;)<\/span> for absolute path handling<\/li>\n<\/ul>\n<\/li>\n<li>\n<h3>&#8220;Login Failed in CI\/CD pipelines&#8221;<\/h3>\n<ul style=\"list-style-type: disc;\">\n<li><span style=\"color: #008000;\">.env<\/span> credentials not loaded properly in your pipeline<\/li>\n<li>Solution: Make sure to set environment variables in your CI setting (like GitHub, Gitlab, and etc.).<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<h2>Best Practices<\/h2>\n<ul>\n<li>Keep login logic separate (as you have done in your <span style=\"color: #008000;\">Login.ts<\/span> page object, which keeps your setup maintainable<\/li>\n<li><strong>Use <span style=\"color: #008000;\">.env<\/span> file<\/strong> for sensitive credentials \u2014 never hard code sensitive data<\/li>\n<li><strong>Ignore storage files<\/strong> in Git<\/li>\n<li><strong>Ignore .env files<\/strong> in Git<\/li>\n<\/ul>\n<h2>Pro And Cons<\/h2>\n<ul style=\"list-style-type: disc;\">\n<li>\n<h3>Pro<\/h3>\n<ul style=\"list-style-type: circle;\">\n<li>Faster test execution<\/li>\n<li>More stable tests<\/li>\n<li>Less maintenance<\/li>\n<li>Better parallel execution<\/li>\n<li>Easier test writing<\/li>\n<\/ul>\n<\/li>\n<li>\n<h3>Cons<\/h3>\n<ul style=\"list-style-type: circle;\">\n<li>Session expiry<\/li>\n<li>Login flow tested only once<\/li>\n<li>Extra Setup to manage session file<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2>Setting up Global Setup for Session Storage In Playwright<\/h2>\n<ul>\n<li>To implement session reusability in Playwright, we first need to create a <span style=\"color: #008000;\">global-setup<\/span> file. In this file, we perform the login action once, fetch the authenticated <strong>session storage state,\u00a0<\/strong>and then store it in a file for example <span style=\"color: #008000;\">sessionStorage.json<\/span> (you can name it as per your preference)<\/li>\n<li>Next, we configure this<strong> global setup file<\/strong> inside the Playwright config so that it runs <strong>before all tests<\/strong>. This ensures the login session is created only once.<\/li>\n<li>Then, under the <strong>use<\/strong> <strong>block<\/strong> (or within the specific project configuration), we reference the same <strong>sessionStorage.json<\/strong> file so that all subsequent tests can <strong>reuse the saved session state<\/strong> without logging in again<\/li>\n<\/ul>\n<h3>Code<\/h3>\n<p>Global Setup File Structure<\/p>\n<pre>import {chromium, FullConfig} from \"@playwright\/test\";\r\nimport path from 'path';\r\nimport { config as dotenv } from 'dotenv';\r\nimport { LOGIN } from '.\/tests\/Pages\/Login';\r\n\r\n\r\ndotenv(); \/\/ Load environment variables\r\n\r\nasync function globalSetup(config: FullConfig) {\r\n\/\/ Launch browser\r\nconst browser = await chromium.launch({ headless: true });\r\nconst page = await browser.newPage();\r\nconst loginPage = new LOGIN(page);\r\n\r\n\/\/ Get base URL from playwright config\r\nconst baseURL = config.projects[0].use?.baseURL as string;\r\n\r\n\/\/ Fetch credentials from .env file\r\nconst email = process.env.ADMIN_EMAIL;\r\nconst password = process.env.ADMIN_PASS;\r\n\r\n\/\/ Navigate to login page\r\nawait page.goto(`${baseURL}\/admin\/users\/login\/`);\r\n\r\n\/\/ Perform login\r\nawait loginPage.performLoginWithValidCred(email, password)\r\n\r\n\/\/ Wait until login completes (adjust URL as needed)\r\nawait page.waitForURL(`${baseURL}\/admin\/dashboard`);\r\n\r\n\/\/ Save session state in a single file\r\nconst storageFile = path.resolve(__dirname, 'sessionStorage.json');\r\nawait page.context().storageState({ path: storageFile });\r\nconsole.log(`Session saved to: ${storageFile}`);\r\n await browser.close();\r\n}\r\nexport default globalSetup;<\/pre>\n<p>Config File Structure<\/p>\n<pre>import { defineConfig, devices } from '@playwright\/test';\r\nimport { config as dotenv } from 'dotenv';\r\n\r\ndotenv();\r\nexport default defineConfig({\r\n    testDir: '.\/tests',\r\n    fullyParallel: false,\r\n    forbidOnly: !!process.env.CI,\r\n    retries: process.env.CI ? 2 : 0,\r\n    workers: process.env.CI ? 1 : undefined,\r\n    reporter: 'html',\r\n    timeout: 90000,\r\n\r\n    \/\/ Run global setup once before all tests\r\n    globalSetup: '.\/global-setup.ts',\r\n\/\/ Global use block with session storage\r\nuse: {\r\n   baseURL: 'https:\/\/dev.example.com', \/\/ your base URL\r\n   storageState: '.\/sessionStorage.json', \/\/ single session file\r\n   trace: 'on-first-retry',\r\n   screenshot: 'only-on-failure',\r\n},\r\n\r\n projects: [\r\n{\r\n  name: 'chromium',\r\n  ...devices['Desktop Chrome']\r\n   }],\r\n});\r\n<\/pre>\n<h2>Wrapping It Up<\/h2>\n<p>Session reusability in Playwright is a game-changer for modern test automation.<br \/>\nBy Saving and reusing the login state we:<\/p>\n<ul>\n<li>Cut down repetitive steps<\/li>\n<li>Speed up execution<\/li>\n<li>Maintain cleaner code<\/li>\n<\/ul>\n<p>Whether you&#8217;re running locally or in CI\/CD pipeline, <strong>this approach ensures &#8220;Login once, test everything&#8221;<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In Automation Testing logging into an application repeatedly for every test case can be time-consuming and inefficient as well. To rescue with this problem Session Storage state comes to picture with narrative of &#8220;Modern Day Problems Require Modern Day Solution&#8221; By saving the authenticated state once and reusing it across multiple tests, automation engineer can [&hellip;]<\/p>\n","protected":false},"author":2193,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":543},"categories":[5880],"tags":[8207,8206,8203,8205,8204],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/76679"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/2193"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=76679"}],"version-history":[{"count":7,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/76679\/revisions"}],"predecessor-version":[{"id":76739,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/76679\/revisions\/76739"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=76679"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=76679"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=76679"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}