teone
teone

Reputation: 2183

Protractor - empty local storage

I'm using Protractor (with Jasmine) to test my AngulaJs application.

As result of some of my action I get some data saved in the localStorage. Now I need to test other case, so I need to empty my storage (or better delete only some items) but If I try to run:

browser.executeScript('localStorage.removeItem("config");');

I get the following error:

UnknownError: <unknown>: Failed to read the 'localStorage' property from 'Window': Storage is disabled inside 'data:' URLs.
  (Session info: chrome=35.0.1916.153)
  (Driver info: chromedriver=2.10.267517,platform=Mac OS X 10.9.2 x86_64)

Any idea on how to solve?

Thanks in advance

Upvotes: 27

Views: 29959

Answers (6)

Sergey Pleshakov
Sergey Pleshakov

Reputation: 8948

If you want the full control of your storage, use this class

class Storage {
    constructor(storage) {
        // 'localStorage' or 'sessionStorage'
        this.storage = storage;
    }

    /**
     * get local/session storage as object
     * @returns {Promise<Object>}
     */
    async get() {
        log(`${this.storage}.get()`);
        let keys = await browser.executeScript(`return Object.keys(window.${this.storage});`),
            storage = {};

        for (let key of keys) {
            storage[key] = await browser.executeScript(`return window.${this.storage}.getItem('${key}');`);
        }

        return storage;
    }

    /**
     * Clear local/session storage
     * @returns null
     */
    async clear() {
        log(`${this.storage}.clear()`);
        return browser.executeScript(`return window.${this.storage}.clear();`);
    }

    /**
     * Set a value of local/session storage
     * @param key
     * @param value
     * @returns
     */
    async setValue(key, value) {
        log(`${this.storage}.setValue(${key}, ${value})`);
        return browser.executeScript(`return window.${this.storage}.setItem('${key}', '${value}');`);
    }

    /**
     * Get value of a key of local/session storage
     * @param key
     * @returns
     */
    async getValue(key) {
        log(`${this.storage}.getValue(${key})`);
        return browser.executeScript(`return window.${this.storage}.getItem('${key}');`);
    }

    async removeItem(key) {
        log(`${this.storage}.removeItem(${key})`);
        return browser.executeScript(`return window.${this.storage}.removeItem('${key}');`);
    }
}

and then use it

let sessionStorage = new Storage('sessionStorage'),
    localStorage = new Storage('localStorage');

// get storage as JSON
console.log(await sessionStorage.get())
// clear storage
await localStorage.clear();
// set key
await localStorage.setValue('key', 'value');
// and many more

Upvotes: 0

Guntram
Guntram

Reputation: 980

If there's still a problem with the localStorage when executing a "removeItem()", you can use a try-catch, like:

browser.executeScript("try {localStorage.removeItem('access_token');} catch(exception) {}");

Upvotes: 3

zayquan
zayquan

Reputation: 8062

I solved this issue by checking the window.location before attempting to clear/modify sessionStorage or localStorage.

If a page has not been loaded then window.location.hostname will equal the empty string ''. So if you get the emptystring, then don't attempt to interact with sessionStorage or localStorage.

Here's some (ES6) code I used in my protractor suite to prevent this error. Note it's a cucumber-js After function, but it is still executed from protractor using chrome, and it demonstrates what you need to do to avoid this error:

this.After(function(scenario) {

  function getWindowLocation() {
    return window.location;
  }

  function clearStorage() {
    window.sessionStorage.clear();
    window.localStorage.clear();
  }

  return browser.executeScript(getWindowLocation).then(function(location) {
    // NB If no page is loaded in the scneario then calling clearStorage will cause exception
    // so guard against this by checking hostname (If no page loaded then hostname == '')
    if (location.hostname.length > 0) {
      return browser.executeScript(clearStorage);
    }
    else {
      return Promise.resolve();
    }
  });
});

Upvotes: 5

Jed Richards
Jed Richards

Reputation: 12437

It's because you haven't navigated to a valid url yet. Do a browser.get('/foo') before trying to interact with page objects like localStorage.

Upvotes: 19

Anthony Panozzo
Anthony Panozzo

Reputation: 3474

Another potential solution is to put any state clearing in an afterEach, which will run after any test is run: (see https://github.com/angular/protractor/issues/188)

afterEach(function() {
    browser.executeScript('window.sessionStorage.clear();');
    browser.executeScript('window.localStorage.clear();');
});

Upvotes: 41

teone
teone

Reputation: 2183

I haven't found a cool way to do that, but if I run my statement

 browser.executeScript("localStorage.removeItem('config');")

within a it('description') statement it works. Example:

it('should compile and save base config for billing',function(){
    browser.executeScript("localStorage.removeItem('config');")

    //my test
});

This remove the item named config, and so my test works, but while searching and talking about this issue the main response I got is:

"localStorage is not you product, so you don't need (read: you must not) test it. The right way is to mock it and inject it contents when they are needed"

I'm still looking into this to understrand how, meanwhile I think that a not philosophically perfect test is still better than nothing so..

Hope this helps...

Upvotes: 3

Related Questions