Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enzyme@3: wrapper is not updated even if there was a new render #1153

Closed
deepsweet opened this Issue Sep 26, 2017 · 40 comments

Comments

Projects
None yet
@deepsweet
Copy link
Contributor

deepsweet commented Sep 26, 2017

Hi. Just faced this after updating to v3.

Given the following deps:

├─ enzyme-adapter-react-16@1.0.0
├─ enzyme@3.0.0
├─ react-dom@16.0.0
├─ react-test-renderer@16.0.0
└─ react@16.0.0

And the HOC:

import React, { Component } from 'react'

const testHOC = (Target) => class TestClass extends Component {
  constructor (...args) {
    super(...args)

    this.state = {}
    this.onTest = this.onTest.bind(this)
  }

  onTest () {
    this.setState({
      foo: true
    })
  }

  render () {
    console.log(this.state)

    return (
      <Target {...this.props} {...this.state} onTest={this.onTest} />
    )
  }
}

export default testHOC

And the test:

import React from 'react'
import { mount } from 'enzyme'
import testHOC from './testHOC'

describe('testHOC', () => {
  it('should work', () => {
    const Target = () => null
    const EnhancedTarget = testHOC(Target)
    const wrapper = mount(
      <EnhancedTarget />
    )

    wrapper.find(Target).prop('onTest')()

    console.log(
      wrapper.debug()
    )
  })
})

I see:

  console.log testHOC.js:18
    { foo: true }

  console.log testHOC.spec.js:15
    <TestClass>
      <Target onTest={[Function]} />
    </TestClass>

So the was a new render, but wrapper just didn't react to it. Works fine with v2.

Please correct me if I was wrong all this time and test should be written in another way.

@ljharb

This comment has been minimized.

Copy link
Member

ljharb commented Sep 26, 2017

Wrappers are immutable in enzyme 3; this is in the migration docs.

Try wrapper.update() after invoking your function.

@deepsweet

This comment has been minimized.

Copy link
Contributor Author

deepsweet commented Sep 26, 2017

Already tried and now re-tried, same result.

@j4k

This comment has been minimized.

Copy link

j4k commented Sep 26, 2017

I'm also experiencing the same behaviour with the same deps on some of my component tests (non-HOC) where the state updates, but the wrapper does not, even after calling .update().

Placing console.log's in the component under tests render method show's things rendering correctly during the test, I just can't seem to assert properly after an .update(), .debug() outputs the initial component. .state() shows the correct state after an .update()

@yesmeck

This comment has been minimized.

Copy link
Contributor

yesmeck commented Sep 27, 2017

I'm also experiencing the similar behavior when using conditional rendering, here is a reproduction repo https://github.com/yesmeck/enzyme-set-props-bug.

@yesmeck

This comment has been minimized.

Copy link
Contributor

yesmeck commented Sep 27, 2017

I created a separate issue #1163.

@j-s-n

This comment has been minimized.

Copy link

j-s-n commented Sep 27, 2017

Same issue. I can confirm that render is running appropriately, and I can even get the updated values from wrapper.state, but wrapper.update doesn't reflect the re-rendered component.

@iantanwx

This comment has been minimized.

Copy link

iantanwx commented Sep 28, 2017

Same issue here.

@deepsweet deepsweet referenced this issue Sep 28, 2017

Closed

React 16 #6

3 of 3 tasks complete
@gziolo

This comment has been minimized.

Copy link

gziolo commented Sep 29, 2017

I did some heave debugging for WordPress/gutenberg#2813 and it looks like we are having the same kind of issues that are reported in this thread and here.

I tried to add recommended wrapper.update(); call after the click event is simulated, but it didn't help. It's quite interesting scenario because the part of the component that depends on the component's state (https://github.com/WordPress/gutenberg/blob/ad316ab1f8cfe60aeeb45ff27d45336bfb214c3c/editor/inserter/menu.js#L384) gets properly updated, but the other part (https://github.com/WordPress/gutenberg/blob/ad316ab1f8cfe60aeeb45ff27d45336bfb214c3c/editor/inserter/menu.js#L366) which also is conditionally rendered based on the components' state doesn't show up in the output of wrapper.debug() call. When I debugged it turned out that React component does everything properly behind the scenes. It looks like Enzyme gets out of sync.

@tleunen

This comment has been minimized.

Copy link

tleunen commented Sep 29, 2017

Confirmed what @gziolo said. The component is updated properly. .html() returns the right structure. But the ReactWrapper itself is out of sync.

@lelandrichardson

This comment has been minimized.

Copy link
Collaborator

lelandrichardson commented Oct 3, 2017

This is hopefully fixed in enzyme-adapter-react-16@1.0.1. Please upgrade and let us know if it does not fix your issue. Thanks!

@mrbinky3000

This comment has been minimized.

Copy link

mrbinky3000 commented Nov 27, 2017

This seems to still be an issue in enzyme-adapter-react-16@1.1.0 wrapper.update() does not work. Yet console logs in the source code show that state is being updated. .html() shows the correct structure. I can point you to a repo with the failing test if that helps.

@ljharb

This comment has been minimized.

Copy link
Member

ljharb commented Nov 28, 2017

@mrbinky3000 .html() isn't as useful as .debug(), what does that show?

@mrbinky3000

This comment has been minimized.

Copy link

mrbinky3000 commented Nov 28, 2017

ImageWithZoom has a state property named "hovering". It starts off false as expected.

  console.log src/ImageWithZoom/ImageWithZoom.jsx:89
    ImageWithZoom.render() state { isImageLoading: false,
      hovering: false,
      style: {},
      x: null,
      y: null }

This is a debug() dump of the wrapper before the mouseover event.

  console.log src/ImageWithZoom/__tests__/ImageWithZoom.test.jsx:38
    before mouseover debug:
     <ImageWithZoom src="bob.jpg" tag="div">
      <div className="container">
        <Wrapper className="image carousel__zoom-image" tag="div" src="bob.jpg" isBgImage={true} onLoad={[Function]} onError={[Function]}>
          <Image hasMasterSpinner={false} orientation="horizontal" className="image carousel__zoom-image" tag="div" src="bob.jpg" isBgImage={true} onLoad={[Function]} onError={[Function]} carouselStore={{...}} alt="" height={{...}} renderError={{...}} renderLoading={{...}} style={{...}}>
            <div className="image carousel__image carousel__image--with-background carousel__image--success image carousel__zoom-image" style={{...}} orientation="horizontal" height={{...}} />
          </Image>
        </Wrapper>
        <Wrapper className="overlay carousel__zoom-image-overlay" tag="div" src="bob.jpg" style={{...}} isBgImage={true} onMouseOver={[Function]} onMouseOut={[Function]} onMouseMove={[Function]}>
          <Image hasMasterSpinner={false} orientation="horizontal" className="overlay carousel__zoom-image-overlay" tag="div" src="bob.jpg" style={{...}} isBgImage={true} onMouseOver={[Function]} onMouseOut={[Function]} onMouseMove={[Function]} carouselStore={{...}} alt="" height={{...}} onError={{...}} onLoad={{...}} renderError={{...}} renderLoading={{...}}>
            <div className="image carousel__image carousel__image--with-background carousel__image--success overlay carousel__zoom-image-overlay" style={{...}} orientation="horizontal" onMouseOver={[Function]} onMouseOut={[Function]} onMouseMove={[Function]} height={{...}} />
          </Image>
        </Wrapper>
      </div>
    </ImageWithZoom>

This is the .html() of the wrapper before the mouseover event is triggered.

  console.log src/ImageWithZoom/__tests__/ImageWithZoom.test.jsx:39
    before mouseover html:
     <div class="container"><div class="image carousel__image carousel__image--with-background carousel__image--success image carousel__zoom-image" orientation="horizontal" style="background-image: url(bob.jpg); background-size: cover;"></div><div class="image carousel__image carousel__image--with-background carousel__image--success overlay carousel__zoom-image-overlay" orientation="horizontal" style="background-image: url(bob.jpg); background-size: cover;"></div></div>

This is a console log in the ImageWithZoom component to acknowledge that our mouseover method was called. It sets the state property "hovering" to true.

  console.log src/ImageWithZoom/ImageWithZoom.jsx:41
    ImageWithZoom.handleOnMouseOver()

This console log is from the ImageWithZoom render method. It shows that the "hovering" state property is now true, as expected.

  console.log src/ImageWithZoom/ImageWithZoom.jsx:89
    ImageWithZoom.render() state { isImageLoading: false,
      hovering: true,
      style: {},
      x: null,
      y: null }

This .html() dump shows that the component has added the class 'carousel__zoom-image-overlay--hovering' in response to the state property "hovering" now being true.

  console.log src/ImageWithZoom/__tests__/ImageWithZoom.test.jsx:41
    after mouseover html:
     <div class="container"><div class="image carousel__image carousel__image--with-background carousel__image--success image carousel__zoom-image" orientation="horizontal" style="background-image: url(bob.jpg); background-size: cover;"></div><div class="image carousel__image carousel__image--with-background carousel__image--success overlay carousel__zoom-image-overlay hover carousel__zoom-image-overlay--hovering" orientation="horizontal" style="background-image: url(bob.jpg); background-size: cover;"></div></div>

However, Enzyme has not been updated to reflect the state change. The css class "carousel__zoom-image-overlay--hovering" is missing. Hence, my tests fail.

  console.log src/ImageWithZoom/__tests__/ImageWithZoom.test.jsx:42
    after mouseover debug
     <ImageWithZoom src="bob.jpg" tag="div">
      <div className="container">
        <Wrapper className="image carousel__zoom-image" tag="div" src="bob.jpg" isBgImage={true} onLoad={[Function]} onError={[Function]}>
          <Image hasMasterSpinner={false} orientation="horizontal" className="image carousel__zoom-image" tag="div" src="bob.jpg" isBgImage={true} onLoad={[Function]} onError={[Function]} carouselStore={{...}} alt="" height={{...}} renderError={{...}} renderLoading={{...}} style={{...}}>
            <div className="image carousel__image carousel__image--with-background carousel__image--success image carousel__zoom-image" style={{...}} orientation="horizontal" height={{...}} />
          </Image>
        </Wrapper>
        <Wrapper className="overlay carousel__zoom-image-overlay" tag="div" src="bob.jpg" style={{...}} isBgImage={true} onMouseOver={[Function]} onMouseOut={[Function]} onMouseMove={[Function]}>
          <Image hasMasterSpinner={false} orientation="horizontal" className="overlay carousel__zoom-image-overlay" tag="div" src="bob.jpg" style={{...}} isBgImage={true} onMouseOver={[Function]} onMouseOut={[Function]} onMouseMove={[Function]} carouselStore={{...}} alt="" height={{...}} onError={{...}} onLoad={{...}} renderError={{...}} renderLoading={{...}}>
            <div className="image carousel__image carousel__image--with-background carousel__image--success overlay carousel__zoom-image-overlay" style={{...}} orientation="horizontal" onMouseOver={[Function]} onMouseOut={[Function]} onMouseMove={[Function]} height={{...}} />
          </Image>
        </Wrapper>
      </div>
    </ImageWithZoom>

Here is the test.

  it('should add hovering classes to the overlay when mouse is hovering', () => {
    expect(imageWithZoom.find('div.overlay').hasClass('hover')).toBe(false);
    expect(imageWithZoom.find('div.overlay').hasClass('carousel__zoom-image-overlay--hovering')).toBe(false);

    console.log('before mouseover debug:\n', imageWithZoom.debug());
    console.log('before mouseover html:\n', imageWithZoom.html());
    imageWithZoom.find('Wrapper.overlay').simulate('mouseover');
    wrapper.update(); // doesn't matter if this is here or not, it still fails the test.
    console.log('after mouseover html:\n', imageWithZoom.html());
    console.log('after mouseover debug\n', imageWithZoom.debug());

    expect(imageWithZoom.find('div.overlay').hasClass('hover')).toBe(true);
    expect(imageWithZoom.find('div.overlay').hasClass('carousel__zoom-image-overlay--hovering')).toBe(true);
  });

I made a branch in my repo that you can check out if you need it.
https://github.com/express-labs/pure-react-carousel/tree/share/sharing-with-enzyme-author

@ljharb

This comment has been minimized.

Copy link
Member

ljharb commented Nov 29, 2017

@mrbinky3000 thanks; can you file this separately?

@mrbinky3000

This comment has been minimized.

Copy link

mrbinky3000 commented Nov 29, 2017

@ljharb I created issue #1400

Thanks for looking into this.

@mrt123

This comment has been minimized.

Copy link

mrt123 commented Jan 11, 2018

This is (actually isn't ... see update below) still an issue in:
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"react-test-renderer": "^16.2.0",

In my case, component triggers a fetch in componentDidMount, which is mocked and confirmed to get triggered. Also tested component successfully re-renders during test.

wrapper.debug() still returns outdated components, and assertions fail.

 jest.spyOn(global, 'fetch').mockImplementation(() => Promise.resolve({
		json: () => myData,
}));

it('renders Dashboard with Loader active', () => {
	const wrapper = mount(<Dashboard />);
	wrapper.update();
	// console.log(wrapper.debug());
	expect(wrapper.find('Dashboard')).toHaveLength(1);
	expect(wrapper.find('RouteContentLoader')).toHaveLength(0);  // This still returns 1
	expect(wrapper.find(SpinnerSvg1)).toHaveLength(0);    // This still returns 1
});

----- UPDATE:
This does not appear to be an issue anymore. Problem was due to my own implementation. In order to update the wrapper I had to ensure promise provided in the fetch mock is fully resolved (which depending on implementation may require multiple then callbacks):

const metrics = { myStuff: 1 };

const dataPromise = Promise.resolve({
	json: () => metrics,
});
jest.spyOn(global, 'fetch')
	.mockImplementation(() => dataPromise);
//.....

// in test
	return dataPromise.then().then(() => {
		wrapper.update();  // will only work if called in last then callback
		//expect(wrapper....);
	});
@mkermani144

This comment has been minimized.

Copy link

mkermani144 commented Jan 28, 2018

This no longer seems to be an issue for me in the following versions:

enzyme: 3.3.0
enzyme-adapter-react-16: 1.1.1
react-test-renderer: 16.2.0

I had exactly the same issue with shallow and wrapper.update() solved the problem. The problem was that I was updating state by calling some props of the wrapper children and enzyme didn't know that some state changes may happen, so it didn't update automatically (as stated here).

@Duskfall

This comment has been minimized.

Copy link

Duskfall commented Apr 13, 2018

Same problem here.
setState is inside the method I am trying to test.
So when calling the method from the test and even when I do a wrapper.update the state of the component isn't updated. I have tried both with mount and shallow

test.js

const wrapper = shallow(<Panel {...props} />);
const appInstance = wrapper.instance();

appInstance.handleChange(data);

panel.js

handleChange(data){
   this.setState({
       test: data
   })
}
@jneander

This comment has been minimized.

Copy link

jneander commented Apr 29, 2018

This appears to remain an issue in enzyme-adapter-react-15@1.0.5. Will the fix be backported for earlier versions of React/Adapters?

@diablouma

This comment has been minimized.

Copy link

diablouma commented Apr 30, 2018

I'm also using the react adapter for React 15 and having the same issue, please let us know if you are going to implement the fix for this adapter. Thanks.

@createthis

This comment has been minimized.

Copy link

createthis commented May 3, 2018

@jneander and @diablouma I don't think wrapper.update() is broken in enzyme-adapter-react-15@1.0.5. I'm running 1.0.5 now and it works for me.

I spent some time (hours) debugging a similar issue this afternoon. In my case, the issue was that I was doing this:

wrapper.find('form').simulate('submit');
wrapper.update();

And expecting simulate to be synchronous. It wasn't. I had an await inside my event handler and when execution hit that await it surrendered execution from the event handler back to the test briefly. NOTE that I am not saying await did not wait successfully. It did, from the perspective of the event handler. However, from the perspective of the test itself, it didn't. I'm not sure what the technical term for that is, but you can imagine that they are two separate async processes running at the same time and control briefly switched from the event handler process to the test process.

You can test this the old school way by putting a ton of console.log('before such and such') statements all throughout your test and your event handler and see what order they are printed when the test executes.

The issue is that events in JS do not return promises. So there is no way to do the equivalent of this:

await wrapper.find('form').simulate('submit');
wrapper.update();

However, event handlers can return promises. So the solution, in my case, was to call the event handler directly, rather than use simulate. Example, where handleSubmit() is my event handler:

let fakeEvent = {preventDefault(){}};
await wrapper.instance().handleSubmit(fakeEvent);
wrapper.update();

I got this idea from the owner of the enzyme repo in this comment: #1054 (comment)

He says:

Personally I think simulate should never be used - there's no common, reliable way for the event handler code to communicate to enzyme when its possibly async actions are completed. What I'd recommend is making your event handlers always return a promise; if you setState in them, resolve that promise in the setState callback; and then instead of ever using simulate, get the prop manually and invoke it directly in your tests.

Hope that helps someone save some time. (Also, I hope I'm on the right track here)

@StefanSmith

This comment has been minimized.

Copy link

StefanSmith commented May 26, 2018

Hi,

In case this helps anyone, I was also struggling with this issue, specifically where a component was asynchronously fetching data in componentDidMount. The data was being retrieved from a stub function that returns Promise.resolve(data). A tip I picked up from http://engineering.pivotal.io/post/react-integration-tests-with-enzyme sent me in the right direction. I simply needed to defer my wrapper.update() till after the promise resolves, which is easy to predict in the case of Promise.resolve(...).

// Mount component, which will asynchronously retrieve data in componentDidMount()
const wrapper = mount(<App/>);

// Block test until event loop has processed any queued work (including our data retrieval)
await new Promise((resolve) => setTimeout(resolve, 0));

// Update as normal
wrapper.update();

// Assert
expect(...)

Versions:

"enzyme": "3.3.0",
"enzyme-adapter-react-16": "1.1.1",
"jest-enzyme": "4.2.0",
"react-test-renderer": "16.4.0"
@robin-drexler

This comment has been minimized.

Copy link

robin-drexler commented Jun 1, 2018

We have encountered a similar issue (please let me know if If got yours wrong) and created a codesandbox to demo/reproduce. The test is in enzyme.spec.js and you have to click on the tests tab at the bottom.

Consider the following small component:

class Item extends Component {
  state = { clicked: false };
  render() {
    return (
      <div>
        <span
          data-clicked={this.state.clicked}
          onClick={() => {
            this.setState(state => ({ clicked: !state.clicked }));
          }}
        >
          test
        </span>
      </div>
    );
  }
}

Whenever I click the span, the data-clicked prop should change.
Here is a test that fails, but imo should work:

it("should work without re-querying", () => {
    const rendered = mount(<Item />);

    const span = rendered.find("span");
    expect(span.prop("data-clicked")).toBe(false);

    span.simulate("click");
    rendered.update(); // calling update also does not seem to help
    expect(span.prop("data-clicked")).toBe(true);
  });

However, if you re-query the span after clicking it, it works.

  it("should work with re-querying", () => {
    const rendered = mount(<Item />);

    let span = rendered.find("span");
    expect(span.prop("data-clicked")).toBe(false);

    span.simulate("click");
    span = rendered.find("span");

    expect(span.prop("data-clicked")).toBe(true);
  });

I wonder if that is intended behavior? We often run into troubles due to that.
Thank you. :)

@mieszko4

This comment has been minimized.

Copy link

mieszko4 commented Jun 6, 2018

I had a similar issue with wrapper not being updated and I think there might be a confusion regarding usage of wrapper.update().

@ljharb wrote that it is immutable and example http://airbnb.io/enzyme/docs/api/ShallowWrapper/update.html shows its usage in non-immutable way.

👎 Anyway, for my case the following did not work for me:

const wrapper = mount(<Component />);
// do some stuff with wrapper...
wrapper.update();
expect(wrapper).toMatchSnapshot();

👍 But, the following did work as expected:

let wrapper = mount(<Component />);
// do some stuff with wrapper...
wrapper = wrapper.update(); // NOTE immutable usage
expect(wrapper).toMatchSnapshot();

Should http://airbnb.io/enzyme/docs/api/ShallowWrapper/update.html example be corrected?

@ljharb

This comment has been minimized.

Copy link
Member

ljharb commented Jun 30, 2018

@mieszko4 "immutable" wasn't meant to mean "nothing can ever change", or else there wouldn't be a setProps or setState method. It's more that wrappers won't rerender automatically, and sub-wrappers aren't connected to the root wrapper.

If the docs can be improved, a PR is always welcome.

@maloguertin

This comment has been minimized.

Copy link

maloguertin commented Aug 7, 2018

Is this supposed to be fixed?

I have this code:

const wrapper = mount(<Component/>)
// simulate event
console.log(wrapper.html())
console.log('length', wrapper.find('.edit-choice').length)

results:

//html()
//includes element with className edit-choice

//wrapper.find()
//length 0
@ljharb

This comment has been minimized.

Copy link
Member

ljharb commented Aug 7, 2018

@maloguertin it's pretty hard to tell when you elide parts of the code; however it's likely that you need a wrapper.update() after you simulate the event. Separately, use .debug(), not .html(), since the latter does a full render.

@ljharb

This comment has been minimized.

Copy link
Member

ljharb commented Sep 1, 2018

This is an old issue that's very long, and there's been numerous updates since all of the comments.

I'm going to close this, since it's not clear to me what's still broken.

If you're still having trouble, please do file a new issue, with a clear repro step, filling out the template - and we'll get it addressed ASAP.

@ljharb ljharb closed this Sep 1, 2018

@lucasdeassis

This comment has been minimized.

Copy link

lucasdeassis commented Sep 3, 2018

Tried all suggestions here and didn't work. At the end updating to "enzyme-adapter-react-16": "^1.3.1" worked.

@guofei0723

This comment has been minimized.

Copy link

guofei0723 commented Dec 14, 2018

"react": "^16.4.1",
"enzyme": "^3.7.0",
"enzyme-adapter-react-16": "^1.7.0",

same issue

update
it is not the same issue in my case. enzyme does not output the error message which happened in render() of my component, and that makes looks like does not re-render

@ljharb

This comment has been minimized.

Copy link
Member

ljharb commented Dec 14, 2018

@guofei0723 please file a new issue if you're having trouble.

@pvanny1124

This comment was marked as outdated.

Copy link

pvanny1124 commented Jan 6, 2019

Hey Everyone!

If you are still having issues with your components not rendering on time before an expect, make your test async and try doing:

await wrapper.update()

before the expect and it should work just fine!

@ljharb

This comment was marked as outdated.

Copy link
Member

ljharb commented Jan 6, 2019

@pvanny1124 Note that doesn’t do what you expect - you’re awaiting a non-promise, so all that does is adds an extra tick. If that works for you, then all that means is that you’re winning your race condition.

@pvanny1124

This comment has been minimized.

Copy link

pvanny1124 commented Jan 6, 2019

@pvanny1124

This comment has been minimized.

Copy link

pvanny1124 commented Jan 6, 2019

@ljharb

This comment has been minimized.

Copy link
Member

ljharb commented Jan 6, 2019

Whatever async stuff you’re doing in your component, you have to intercept in your tests so that you can reliably await that.

If you have further questions, please file a new issue.

@Finesse

This comment has been minimized.

Copy link

Finesse commented Feb 10, 2019

I had a similar issue. I fixed it by replacing

const wrapper = mount(<Component />);
const button = wrapper.find('.button');
// Do some stuff with the button...
button.update();
expect(button.prop('type')).toEqual('foo');

with

const wrapper = mount(<Component />);
const button = wrapper.find('.button');
// Do some stuff with the button...
wrapper.update();
expect(wrapper.find('.button').prop('type')).toEqual('foo');

The .update() method must be called on the root wrapper, not on a child wrapper. The method mutates the root wrapper but doesn't mutate any child wrapper so I have to find the button again.

@ljharb

This comment has been minimized.

Copy link
Member

ljharb commented Feb 10, 2019

@Finesse yes, that's part of v3 - you always have to re-find from the root.

@Jlevett

This comment has been minimized.

Copy link

Jlevett commented Mar 11, 2019

I found something that works.
Add these middle two lines.

wrapper .find(...Your thing) .simulate('click'); //Click event on wrapper
await wrapper.instance().forceUpdate(); //THIS ONE
wrapper.update();  //AND THIS ONE
expect(....).toHaveLength(1); //Your assertion here
@Finesse

This comment has been minimized.

Copy link

Finesse commented Mar 11, 2019

@Jlevett Calling forceUpdate can spoil your test because React may skip updates in some cases and you need to check that React has or hasn't skipped the update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.