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

add request cache, change Request to extend Body, fix Body, implemen… #85

Closed
wants to merge 2 commits into from
Closed

add request cache, change Request to extend Body, fix Body, implemen… #85

wants to merge 2 commits into from

Conversation

DomingosMartins
Copy link

add request cache
change Request to extend Body
fix Body
implement client.postmessage to receive a callback function

@@ -2,14 +2,19 @@ const generateRandomId = require('../utils/generateRandomId');

// https://developer.mozilla.org/en-US/docs/Web/API/Client
class Client {
constructor(url, frameType) {
constructor(url, options) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like passing in a postMessageCallback is not part of the Client spec, and causes a backwards incompatibility if someone is passing in frameType currently. Can you provide more details of the reasoning for this?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've passed this callback in order to pass a mocked function to properly test if post-message was called. I can pass is to a different parameter.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool. Can you share a snippet of what your test looks like? We might be able to find a better way than adding non-spec code to the mocks 🤞🏻

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it('should update the clients', async done => {
    const defer = when.defer();
    const clientPostCallback = response => {
        defer.resolve(response);
    };
    const responseBody = { test: 'response' };

    responseMock = new Response(responseBody, { headers: headersMock });
    global.fetch = jest.fn(() => responseMock);
    await clients.openWindow(
        'http://localhost:3000',
        clientPostCallback
    );

    requestMock = new Request('http://localhost:3000/test', {
        cache: 'reload'
    });

    expect(global.fetch.mock.calls.length).toBe(0);
    const response = await self.trigger('fetch', requestMock);
    expect(global.fetch.mock.calls.length).toBe(1);
    expect(response).toEqual(responseMock);

    setTimeout(() => {
        defer.reject('Post message has not been called from the client');
    }, 2000);

    when(defer.promise).then(
        callbackResponse => {
            expect(callbackResponse.data).toEqual(responseBody);
            done();
        },
        failure => {
            done(failure);
        }
    );
});

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome. Can you point me to when in this example postMessage should be called?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the test, it will be called when we intercept the fetch.

Copy link
Author

@DomingosMartins DomingosMartins May 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const updateClients = async (event, response) => {
    const clients = await self.clients.matchAll();
    const data = await response.json();
    const { clientId } = event;
    clients.forEach(client => {
        if (clientId !== client.id) {
            client.postMessage({
                data
            });
        }
    });
};

const cachedResourceOrFetch = async event => {
    // some more logic
    const response = fetch('url');
    updateClients(event, response.clone());
    return response.clone();
};

self.addEventListener('fetch', async event => {
    event.respondWith(cachedResourceOrFetch(event));
});

Copy link
Owner

@zackargyle zackargyle May 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. It's hard to suggest a better way to test it without the full example, but I think the simplest way would be to override the mock on the client itself. That way we're not adding non-spec code to the models themselves.

const client = await clients.openWindow('http://localhost:3000');
client.postMessage = jest.fn();

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ Does that work for you? This should make it easy to verify that postMessage is being called (but that's not really a great unit to test).

I'm trying to have the mocks act exactly like the spec, and adding extra parameters is undesirable. There's no good way to update the postMessage method itself since that talks to a separate DOM environment. The only better way would be to use puppeteer and write a unit test to verify that the postMessage is working correctly in your app.

@@ -15,8 +15,8 @@ class Clients {
return Promise.resolve(this.clients);
}

openWindow(url) {
const client = new Client(url);
openWindow(url, postMessageCallback) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not look like part of the spec.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

} else if (typeof body !== 'object') {
body = undefined;
}
super(body);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the if statements? I think it should just be

constructor(body, init) {
  super(body);
  ...
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you clone the Response the body will be already a Blob

@zackargyle
Copy link
Owner

zackargyle commented May 15, 2018

We disabled Travis on this repo, but somehow your diff got in a weird state with it. I'll be able to get it merged once we resolve comments!

@DomingosMartins
Copy link
Author

Sorry,

I was out for some weeks, I've removed the implementation of the post message.
I thought that this was a good approach to test the postMessage as this is a lib only to unit test the service workers. :)

this.body = body || '';
if (typeof body === 'object' && !(body instanceof Blob)) {
body = JSON.stringify(body);
} else if (typeof body !== 'object') {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain this line? I believe it will break if body is a string.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JSON.stringify() does not break with a string

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typeof 'foo' === 'string', so it won't get into that if statement, instead it will be set to undefined. That's why I was curious about the else if statement. What was the reasoning behind the fallback to undefined?

@sodabrew
Copy link

sodabrew commented Dec 2, 2018

I've found my way to this PR as I'm writing up a test harness for my scripts on Cloudflare's Workers environment. Specifically I found that Response does not currently extend Body, which this PR adds.

Is there anything I can do to help the code review above to move this forward?

(Thank you for this project!)

@zackargyle zackargyle closed this Dec 4, 2018
@zackargyle
Copy link
Owner

Resolved in #92

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants