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

Added new tests directory: webshare. #6287

Merged
merged 18 commits into from Jun 27, 2017
Merged

Conversation

mgiuca
Copy link
Member

@mgiuca mgiuca commented Jun 20, 2017

Adds comprehensive tests for Web Share API drafted here.

Most tests are manual, which is necessary, given the nature of the API (requires user gesture and interaction with user interface).

All the tests pass in Chrome 60 with chrome://flags#enable-experimental-web-platform-features flag enabled, except for the following five (due to Chrome's implementation not matching the spec, bugs are filed and issues are being fixed for Chrome 61).

@wpt-pr-bot
Copy link
Collaborator

There are no owners for this pull request. Please reach out on W3C's irc server (irc.w3.org, port 6665) on channel #testing (web client) to get help with this. Thank you!

@w3c-bots
Copy link

w3c-bots commented Jun 20, 2017

View the complete job log.

Firefox (nightly)

Testing web-platform-tests at revision 1afc4a8
Using browser at version BuildID 20170612100241; SourceStamp 27cad9749cddf68e11fdd4e5d73dad84a8f8cf23
Starting 10 test iterations
All results were stable

All results

4 tests ran
/web-share/idlharness.https.html
Subtest Results Messages
OK
Test driver PASS
Navigator interface: operation share(ShareData) FAIL assert_own_property: interface prototype object missing non-static operation expected property "share" missing
Navigator interface: navigator must inherit property "share" with the proper type (0) FAIL assert_inherits: property "share" not found in prototype chain
Navigator interface: calling share(ShareData) on navigator with too few arguments must throw TypeError FAIL assert_inherits: property "share" not found in prototype chain
/web-share/share-securecontext.http.html
Subtest Results Messages
OK
navigator.share must be undefined in non-secure context PASS
/web-share/share-url-invalid.https.html
Subtest Results Messages
OK
share with an invalid URL FAIL navigator.share is not a function
/web-share/share-without-user-gesture.https.html
Subtest Results Messages
OK
share without a user gesture FAIL navigator.share is not a function

@w3c-bots
Copy link

w3c-bots commented Jun 20, 2017

View the complete job log.

Sauce (safari)

Testing web-platform-tests at revision 1afc4a8
Using browser at version 10.0
Starting 10 test iterations
All results were stable

All results

4 tests ran
/web-share/idlharness.https.html
Subtest Results Messages
OK
WebShare IDL test FAIL SyntaxError: Unexpected token '=>'
/web-share/share-securecontext.http.html
Subtest Results Messages
OK
navigator.share must be undefined in non-secure context PASS
/web-share/share-url-invalid.https.html
Subtest Results Messages
OK
share with an invalid URL FAIL navigator.share is not a function. (In 'navigator.share({url})', 'navigator.share' is undefined)
/web-share/share-without-user-gesture.https.html
Subtest Results Messages
OK
share without a user gesture FAIL navigator.share is not a function. (In 'navigator.share({title: 'the title', text: 'the message',\n url: 'data:the url'})', 'navigator.share' is undefined)

@w3c-bots
Copy link

w3c-bots commented Jun 20, 2017

View the complete job log.

Chrome (unstable)

Testing web-platform-tests at revision 1afc4a8
Using browser at version 61.0.3135.4 dev
Starting 10 test iterations
All results were stable

All results

4 tests ran
/web-share/idlharness.https.html
Subtest Results Messages
OK
Test driver PASS
Navigator interface: operation share(ShareData) FAIL assert_own_property: interface prototype object missing non-static operation expected property "share" missing
Navigator interface: navigator must inherit property "share" with the proper type (0) FAIL assert_inherits: property "share" not found in prototype chain
Navigator interface: calling share(ShareData) on navigator with too few arguments must throw TypeError FAIL assert_inherits: property "share" not found in prototype chain
/web-share/share-securecontext.http.html
Subtest Results Messages
OK
navigator.share must be undefined in non-secure context PASS
/web-share/share-url-invalid.https.html
Subtest Results Messages
OK
share with an invalid URL FAIL navigator.share is not a function
/web-share/share-without-user-gesture.https.html
Subtest Results Messages
OK
share without a user gesture FAIL navigator.share is not a function

@w3c-bots
Copy link

w3c-bots commented Jun 20, 2017

View the complete job log.

Sauce (MicrosoftEdge)

Testing web-platform-tests at revision 61bb50f
Using browser at version 14.14393
Starting 10 test iterations
All results were stable

All results

4 tests ran
/web-share/idlharness.https.html
Subtest Results Messages
OK
WebShare IDL test FAIL Syntax error
/web-share/share-securecontext.http.html
Subtest Results Messages
OK
navigator.share must be undefined in non-secure context PASS
/web-share/share-url-invalid.https.html
Subtest Results Messages
OK
share with an invalid URL FAIL Object doesn't support property or method 'share'
/web-share/share-without-user-gesture.https.html
Subtest Results Messages
OK
share without a user gesture FAIL Object doesn't support property or method 'share'

@@ -0,0 +1,16 @@
<!DOCTYPE html>
Copy link
Member Author

Choose a reason for hiding this comment

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

I was unable to test this file locally; it's supposed to run on a non-secure context but I am testing on localhost because I can't get OpenSSL working. So... does the test runner automatically open "http.html" pages on a non-secure origin? Otherwise this test isn't going to work.

Copy link
Member Author

Choose a reason for hiding this comment

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

It appears the automated testing above is correctly running share-securecontext.http.html on a non-secure origin so I think this is working out.

Copy link
Member

Choose a reason for hiding this comment

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

@mikewest would know for sure, but I think that in order to run on a non-secure origin, you can name the test anything. I don't know if "http.html" means anything, but "https.html" does mean to run it over HTTPS, unsurprisingly.

Copy link
Member

Choose a reason for hiding this comment

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

http.html does not mean anything. As @foolip noted, tests run on a non-secure origin by default.

On your local machine, you should be setting web-platform.test and a few other domains to point to loopback, as outlined in https://github.com/w3c/web-platform-tests#running-the-tests. If you do that, then loading http://web-platform.test:8000/ locally should do the trick.

Copy link
Member Author

Choose a reason for hiding this comment

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

http.html does not mean anything.

Are you sure? The links above in the comment generated by w3c-bots all link to https://w3c-test.org except the http.html file, which links to http://w3c-test.org. It may just be the bot that generates the GitHub comment though, it may not affect the test runner.

On your local machine, you should be setting web-platform.test and a few other domains to point to loopback

Yeah, I've done that and it works there. But that's a manual process. What I'm interested in is the test runner at https://w3c-test.org/tools/runner/index.html --- ideally it should automatically run the http.html test on an http:// URL so I can run the full battery of tests without having to manually run that test on http. Maddeningly I am unable to test this anywhere:

  • On my local machine, I can run http://localhost:8000/tools/runner/index.html. It works great, except the http.html test fails because localhost is a secure context.
  • Still on my local machine, http://web-platform.test:8000 works, but https://web-platform.test:8000 doesn't work (the server prints "Bad HTTP/0.9 request type" / "Bad request syntax" and a bunch of junk, and Chrome says "web-platform.test sent an invalid response"). Despite OpenSSL being installed. So I can't test the behaviour of the test runner switching to http:// locally.
  • https://w3c-test.org/tools/runner/index.html prints "Updating and loading test manifest; this may take several minutes." and it never completes (for any tests), even after an hour. I'm trying it with /payment-request, which has a http.html file. This was working for me a few days ago but hasn't been working for 24 hours.
  • https://w3c-test.org/submissions/6287/tools/runner/index.html (the test runner inside this PR's submission directory) completes for /webshare but shows 0 tests. Trying to test it on /payment-request, it also runs for what seems like forever.

(In my experience with this tool locally, if the server crashes with a Python error locally, the client hangs forever at the "Updating and loading test manifest" step, so maybe there is a server-side crash.) This test runner has been the bane of my existence for the past few days :/

// large).
const url = 'http://example.com:65536';
return promise_rejects(
t, new DOMException(undefined, 'TypeError'),
Copy link
Member Author

@mgiuca mgiuca Jun 20, 2017

Choose a reason for hiding this comment

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

I'm getting this error on Safari (according to bots):

function is not a constructor (evaluating 'new DOMException(undefined, 'TypeError')')

How are you supposed to check for a particular exception type in a way that works in Safari?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think I solved it...

Copy link
Member Author

@mgiuca mgiuca left a comment

Choose a reason for hiding this comment

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

Some comments on my own PR.

@sideshowbarker
Copy link
Contributor

w3c-test:mirror

Adds comprehensive tests for Web Share API drafted here:
https://wicg.github.io/web-share/

Most tests are manual, which is necessary, given the nature of the API
(requires user gesture and interaction with user interface).
@mgiuca
Copy link
Member Author

mgiuca commented Jun 20, 2017

@foolip Just picking you randomly for process questions (and if you're keen, a review). I'm not sure if I need to nominate a reviewer or if one gets assigned automatically (this just says to wait for a review).

Also @w3c-bots automatically ran some tests up above but I've since pushed changes to the branch and it doesn't seem to be running them again, though the Travis ran again. (Not that they would pass on any browser because it's only implemented in Chrome and only behind --enable-experimental-web-platform-features.)

@foolip
Copy link
Member

foolip commented Jun 20, 2017

@foolip Just picking you randomly for process questions (and if you're keen, a review). I'm not sure if I need to nominate a reviewer or if one gets assigned automatically (this just says to wait for a review).

No documentation says this, but I'd recommend when adding a new directory to find more than one owner if possible, so that the other owner can do the reviewing. Ideally one owner for each implementer who is vaguely interested in the space, if you can convince them.

Also @w3c-bots automatically ran some tests up above but I've since pushed changes to the branch and it doesn't seem to be running them again, though the Travis ran again. (Not that they would pass on any browser because it's only implemented in Chrome and only behind --enable-experimental-web-platform-features.)

The existing comments are updated to avoid the PR threads becoming ridiculously long, this may be what you're seeing. Quite soon now this is going to be replaced with a single comment that links to the relevant information instead.

Copy link
Member

@foolip foolip left a comment

Choose a reason for hiding this comment

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

LGTM % nits, if you can find another owner who can give a second opinion that'd be great, but not required.

};
</script>
<script type="text/plain" id="tested">
partial interface Navigator {
Copy link
Member

Choose a reason for hiding this comment

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

Can you put this in interfaces/web-share.idl instead? 8832295 is an example of it, and I hope it'll make it easier to eventually automatically update these IDL files from specs.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

webshare/OWNERS Outdated
@@ -0,0 +1 @@
@mgiuca
Copy link
Member

Choose a reason for hiding this comment

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

Commenting on the first file in the directory. Unless https://wicg.github.io/web-share/ is to be renamed, using web-share as the shortname here as well would be good. That is the general pattern, although I can't find it documented.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm OK, done.

(This seems to be a recurring problem with Web Share. The new name is inconsistent with most of the other names here, like webusb, but there are some precedents.)

<script>
"use strict";
var idl_array = new IdlArray();
idl_array.add_untested_idls(document.querySelector("#untested").textContent);
Copy link
Member

Choose a reason for hiding this comment

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

Doesn't matter, but it's fine to do idl_array.add_untested_idls("interface Navigator {};"); if you like after the big IDL block is gone from the file.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

promise_test(t => {
return callWhenButtonClicked(() => promise_rejects(
t, 'AbortError',
navigator.share({title: 'the title', text: 'the message', url: 'data:the url'})));
Copy link
Member

Choose a reason for hiding this comment

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

Running this test manually without the feature enabled and clicking the button, the test never fails or times out. Can you investigate, and ensure that tests fail fast when the feature doesn't exist?

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed. (It was throwing an exception from an asynchronous context that wasn't being caught by the test runner.)

<html>
<head>
<meta charset="utf-8">
<title>WebShare Manual Test: Share cancelled by user</title>
Copy link
Member

Choose a reason for hiding this comment

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

It's OK to omit "WebShare Manual Test" from all titles, this is clear from context.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

<script>
setup({explicit_timeout: true});

// Exact same test as in share-unicode-strings-manual.html, with same
Copy link
Member

Choose a reason for hiding this comment

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

To verify the preconditions, can you assert_equals(document.characterSet, something)? HTTP headers can ruin it, as could typos in various places.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

Also changed the page from iso-8859-1 to windows-1252. TIL that at least on the Web platform, the latter is the canonical name for the former.

<script>
setup({explicit_timeout: true});

setupManualShareTest(false, '', '', location.toString());
Copy link
Member

Choose a reason for hiding this comment

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

The way the spec is written, the the document's base URL should be used to resolve the URL, can you use document.baseURI here? Even better would be a test where the base URL and the URL are not the same, to catch bugs where the wrong thing is used, but take that as an optional suggestion.

Copy link
Member Author

Choose a reason for hiding this comment

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

Aha, didn't know about baseURI. Updated, and also updated getAbsoluteUrl in the helper file.

I've changed share-url-relative-manual.html to test with a custom <base> to ensure the implementation uses baseURI and not location. Chrome does this correctly.

Related spec bug.

promise_test(t => {
// URL is invalid in that the URL Parser returns failure (port is too
// large).
const url = 'http://example.com:65536';
Copy link
Member

Choose a reason for hiding this comment

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

Love this test too, I've often struggled to find invalid URLs and will keep this one for reference.

<html>
<head>
<meta charset="utf-8">
<title>WebShare Manual Test: Share with URL without a scheme</title>
Copy link
Member

Choose a reason for hiding this comment

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

Should this test and a few of the following not be .https? Otherwise they'll just fail for the wrong reason?

Copy link
Member Author

Choose a reason for hiding this comment

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

I was cargo-culting from other tests in WPT (specifically, geolocation-API) in which every test is either manual or https (but not both). I see other tests with the suffix "-manual.https.html".

Should these all be renamed?

Copy link
Member

Choose a reason for hiding this comment

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

Hmm, so I suppose it actually does not matter because they can only be run manually. When automated, however, they'll need to be over HTTPS, so -manual.https.html SGTM since they already exist. (Hypothetically, one could make a harness for manual runs where the user just sits and clicks.)

<script>
promise_test(t => {
return promise_rejects(
t, 'SecurityError',
Copy link
Member

Choose a reason for hiding this comment

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

This is what the spec says, but if you feel like changing it, I'd argue that user gesture checks are not quite security sensitive, but rather prevent user annoyance. FWIW, https://fullscreen.spec.whatwg.org/ rejects with TypeError.

Copy link
Member Author

Choose a reason for hiding this comment

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

I filed a bug about this. Let's discuss there.

@sideshowbarker
Copy link
Contributor

sideshowbarker commented Jun 21, 2017

This test runner has been the bane of my existence for the past few days :/

Sorry :(

As an alternative, have you considered using wptrun?

It’s intended to make it as easy as possible for you to just run tests from the command line; e.g.:

./wptrun chrome /webshare

That’ll run all the tests in test files in the /webshare directory, and report the results to the console in a human-readable format.

If you want to also get the results in JSON, you can do this:

./wptrun chrome /webshare --log-raw=log.json

Then in that log.json file for each subtest run, you’ll find a {"status":… line/object; e.g.:

{"status": "FAIL", "thread": "Thread-TestrunnerManager-1", "subtest": "Navigator interface: operation share(ShareData)", "pid": 97630, "source": "web-platform-tests", "test": "/webshare/idlharness.https.html", "time": 1498009923527, "action": "test_status", "message": "assert_own_property: interface prototype object missing non-static operation expected property \"share\" missing", "stack": "    at IdlInterface.<anonymous> (https://web-platform.test:8443/resources/idlharness.js:1458:13)\n    at Test.step (https://web-platform.test:8443/resources/testharness.js:1412:25)\n    at IdlInterface.test_member_operation (https://web-platform.test:8443/resources/idlharness.js:1410:12)\n    at IdlInterface.test_members (https://web-platform.test:8443/resources/idlharness.js:1708:26)\n    at IdlInterface.test (https://web-platform.test:8443/resources/idlharness.js:811:10)\n    at self.IdlArray.IdlArray.test (https://web-platform.test:8443/resources/idlharness.js:425:28)", "expected": "PASS"}

That’s a different results format than what /tools/runner/index.html produces, but if you’ve got some processing tool that consumes the /tools/runner/index.html JSON output, I would think it could without too much effort be modified to consume the wpt/wptrunner output format.

@sideshowbarker
Copy link
Contributor

sideshowbarker commented Jun 21, 2017

https://w3c-test.org/tools/runner/index.html prints "Updating and loading test manifest; this may take several minutes." and it never completes (for any tests), even after an hour. I'm trying it with /payment-request, which has a http.html file. This was working for me a few days ago but hasn't been working for 24 hours.
(In my experience with this tool locally, if the server crashes with a Python error locally, the client hangs forever at the "Updating and loading test manifest" step, so maybe there is a server-side crash.)

Yeah that sounds like what may be happening on w3c-test.org but I don’t have the free cycles to try to troubleshoot it.

Instead what I did a day or two ago to try to work around it is, I set up a cron job that runs once an hour at :15 after that deletes the MANIFEST.json file and then runs ./manifest to regenerate it.

I thought that’d prevent the /tools/runner/index.html problem, but based on your comments it sounds like it might’ve instead made things worse. If so, let me know and I’ll remove the cron job.

But the thing is, we don’t have anybody interested in maintaining the /tools/runner/index.html source, so it seems like it’s really not something we should be continuing to encourage anybody to rely on unless/until we have somebody actively maintaining it.

What we have instead is wptrun, as a command-line alternative intended to be easy to use and to solve the same user/information need that people are wanting to use /tools/runner/index.html for.

Allows a more easily-maintainable IDL file in the top-level interfaces
directory.
Fixes silent failure in promise_tests when navigator.share is missing.
Also changed charset from iso-8859-1 to windows-1252 (the canonical name
for the same encoding).
This doesn't matter but technically it's incorrect to use location
because the base URI can be different to the document location.
@mgiuca
Copy link
Member Author

mgiuca commented Jun 21, 2017

I've addressed the comments and uploaded a new version.

Before landing, I can squash the commits down to avoid polluting the repo (but keeping them separate for reviewability). Unless this GitHub is set up to do that automatically...?

@marcoscaceres
Copy link
Contributor

@marcoscaceres You've shown interest in Web Share in the past. Would you like to be a co-OWNER of the web platform tests directory?

Sure, add me. Can help review.

@mgiuca
Copy link
Member Author

mgiuca commented Jun 21, 2017

@marcoscaceres Great, added.

(I put you second instead of alphabetical order so people will bother me more and you less. LMK if you think alphabetical is more appropriate.)

@tobie
Copy link
Contributor

tobie commented Jun 21, 2017

(I put you second instead of alphabetical order so people will bother me more and you less. LMK if you think alphabetical is more appropriate.)

The main botherer is a bot, and it bothers everyone on the list. :)

promise_test(t => {
// URL is invalid in that the URL Parser returns failure (port is too
// large).
const url = 'http://example.com:65536';
Copy link
Contributor

Choose a reason for hiding this comment

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

Safari doesn't seem to care that the port is too large?

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe use a more invalid URL?

Copy link
Contributor

Choose a reason for hiding this comment

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

(Be careful you don't end up testing URL conformance, rather than spec conformance?)

Copy link
Member Author

Choose a reason for hiding this comment

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

Safari doesn't seem to care that the port is too large?

Tried this on Safari 10.1.1 (not Web Share obviously, but new URL('http://example.com:65536')). It correctly throws a TypeError. Not sure what you're seeing, or what version.

Maybe use a more invalid URL?

Not sure what this would be. It's actually quite hard to find an invalid URL string as @foolip pointed out. This is specified as invalid and it seems like a pretty solid one, since the data structure for URL port is an "unsigned 16-bit integer", this value can't fit in there.

(Be careful you don't end up testing URL conformance, rather than spec conformance?)

Do you mean be careful to only test Web Share conformance, not other specs? Sure, but it's hard to do in this case because Web Share needs to fail on an invalid URL, it necessarily means we need to test with a real URL and hope the user agent follows that spec correctly.

Copy link
Contributor

Choose a reason for hiding this comment

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

Apologies, just tried 65536 again and indeed it throws... must have mistyped it when I tried it yesterday.

</head>
<body>
<script>
setup({explicit_timeout: true});
Copy link
Contributor

Choose a reason for hiding this comment

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

I was kinda expecting to see here, as a comment, or in the title, something about the conformance requirement. From this tests, it's not clear what the pass condition is when an empty URL is given.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure what you mean here.

Every manual test in this directory calls setupManualShareTest with the expected outputs (i.e., the expected values to be received by the target), which displays those expectations for the user. In this case, the expectation is that the url field contains document.baseURI.

You can see this page here:
https://w3c-test.org/submissions/6287/web-share/share-url-empty-manual.html

Instructions:

  1. Click the Share button.
  2. Choose a valid share target.

Pass the test iff the target app received:

I think that's sufficient indication of what the manual pass condition is, in each test.

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, I see... Ok, but I shouldn't have to go look at the setupManualShareTest() call site to understand the test. Consider, there is a boolean trap as the first argument of setupManualShareTest, no idea what the second and third arguments are, but can assume what getAbsoluteUrl() does:

 setupManualShareTest(false, '', '', getAbsoluteUrl(url))

Thus, for ones like the above, or globally, I would expect a comment explaining what is being tested (if it's not immediately obvious from just looking at setupManualShareTest()).

If setupManualShareTest() is something that we control, then we should fix it to use a dictionary so it's actually clear what each argument slot does.

Make sense?

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh OK it's more about the person reading the test, not the person manually executing it.

I'm not sure, in some sense this is just a language thing, you should generally be expected to know what the arguments are for a function and if you don't, you go look at the function (not all call sites need to document what the function args are). On the other hand, it would be easier to tell which ones matched which fields if they were dicts. What do you say about leaving the true/false cancel expectation as an argument, but moving all the ShareData expectations into a dictionary?

Copy link
Contributor

Choose a reason for hiding this comment

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

What do you say about leaving the true/false cancel expectation as an argument, but moving all the ShareData expectations into a dictionary?

re: true/false, it's just that I've seen humans be the biggest bottleneck to getting compat issues fixed. We should be minimizing the amount of work anyone who hits a fail needs to do in order to work out what has gone wrong (see also @tobie's comment about having to look up the function signature).

@sideshowbarker, you've been at this for a few years, would you agree?

Copy link
Member Author

Choose a reason for hiding this comment

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

In this case, the implementor doesn't need to read the test unless they disagree with it. They just need to visit the page and do what it says. The true/false here just determines whether the page prints out "Cancel the dialog" or "Choose a target".

So the call to setupManualShareTest should be treated with the same degree of clarity as any ordinary function call in a piece of software, not with some special level of clarity because implementors need to be able to read it. I would suggest we don't need every parameter to be tagged in every function call in JavaScript, and this is no exception. (But I'm happy to go with the flow here if there is consensus.)

Copy link
Contributor

Choose a reason for hiding this comment

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

So the call to setupManualShareTest should be treated with the same degree of clarity as any ordinary function call in a piece of software,

There's abundant literature on how booleans in function signatures are a bad idea overall, e.g. Robert C. Martin in Clean Code:

Passing a boolean into a function is a truly terrible practice. It immediately complicates the signature of the method, loudly proclaiming that this function does more than one thing.

So here's what I would suggest instead; create the two functions:

setupManualShareTest({ title, url, text });
setupManualShareTestRequiringCancellation({ title, url, text }); // bikeshed name at will

This would make it a lot easier to review the tests, understand what they're doing, debug them and write new ones in the future.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done. Much better, thanks for the suggestion.


const url = 'data:foo';
setupManualShareTest(false, '', '', getAbsoluteUrl(url));
callWhenButtonClicked(() => navigator.share({url: url}));
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: just:

callWhenButtonClicked(() => navigator.share({url}));

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

const url = 'https://www.example.com/some/path?some_query#some_fragment';
setupManualShareTest(false, 'the title', 'the message', url);
callWhenButtonClicked(() => navigator.share(
{title: 'the title', text: 'the message', url: url})).then(
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: whitespace

// Check that promise resolved with undefined. This is guarded
// by an if statement because we do not want it to register as a
// test if it passes (since this is a manual test).
if (result !== undefined)
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: wrap if with { } please :)

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

<script>
test(() => {
assert_false('share' in navigator, 'navigator has attribute \'share\'.');
}, 'navigator.share should be undefined in non-secure context');
Copy link
Contributor

Choose a reason for hiding this comment

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

s/should/must/

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

setup({explicit_timeout: true});

// Expect null to be converted into the string 'null'. (This isn't good
// practice, but it's how Web IDL specifies conversion.) On the other
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Maybe drop the note about IDL conversion.

Copy link
Contributor

Choose a reason for hiding this comment

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

Well, especially since that seems like a deliberate choice of the API:

dictionary ShareData {
  USVString title;
  USVString text;
  USVString url;
};

If you want null to be handled properly, why not just do so in the IDL? i.e.:

dictionary ShareData {
  USVString? title;
  USVString? text;
  USVString? url;
};

Copy link
Contributor

Choose a reason for hiding this comment

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

This is a good point actually. Allowing null to equal "this document" instead of empty string might be nice... or is there precedence in the platform for interpreting the empty string as this URL?

Copy link
Member Author

Choose a reason for hiding this comment

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

The note isn't saying it's bad practice for the spec to be defined this way, it's saying it's bad practice for a developer to rely on this (but that it's correct). Regardless, dropped this comment.

If you want null to be handled properly, why not just do so in the IDL? i.e.:

This was a deliberate change in response to feedback: #19. I explicitly want null to be converted to the string "null", just like any other object value is converted into a string. This test just tests that edge case.

I initially declared these nullable but since I've learned more about WebIDL, I think it makes sense to not allow null here. We already allow omission / undefined. Allowing null as a legal value is just an additional case that there is no need for.

Copy link
Contributor

Choose a reason for hiding this comment

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

or is there precedence in the platform for interpreting the empty string as this URL?

well, <a href=""></a>, no?

Copy link
Contributor

Choose a reason for hiding this comment

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

That was my initial reaction too but this isn't really a matter of opinion for an individual standard.
(In summary: yes, it's weird and unintuitive, but very much normal.)

Yup. Agreed. :)

We used to have [TreatNullAs=EmptyString] for that, but as you said, that ship has sailed.

While on that topic, have you considered making "" the default value for some of these (and thus avoiding having to deal with dictionary members that are not present)?

Copy link
Member

Choose a reason for hiding this comment

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

Pointing out strange things in specs and tests about null vs. undefined has become a pet peeve of mine, but I don't actually think what we have is good. I'm not sure that treating null and undefined the same way in dictionaries would have been better, but in any case it's not a change to Web IDL that seems worthwhile at this point.

Copy link
Contributor

Choose a reason for hiding this comment

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

@foolip: which one's the pet peeve? "Strange things in specs and tests about null vs. undefined" or people pointing them out? I'm genuinely unsure which one you mean. :-/

Copy link
Member

Choose a reason for hiding this comment

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

Oh, "pet peeve" means something that annoys you, I didn't mean that. I mean that enjoy pointing out the surprising things about null and undefined, and the tests that exercise them, even though it's not the most important thing in the world.

Copy link
Contributor

Choose a reason for hiding this comment

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

Gotcha! While I agree null vs. undefined isn't the most important thing in the world, it's the kind of thing that cause hard to reproduce issues that developers end up wasting a huge amount of time on and hating the platform for. So making sure sure we're consistent here seems like a good use of ones time.

<html>
<head>
<meta charset="utf-8">
<title>WebShare Test: Surplus arguments ignored</title>
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think you want to test for this. This might cause issues if we need to extend the API later and it's outside the scope of the API.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it makes sense to test this.

Surely if we extend the API later, we'll also extend the test? More importantly, this tests that a valid implementation allows us to extend the API later without breaking backwards-compatibility.

(The tests don't need to be forwards-compatible, but we do need to test that the implementation is forwards-compatible.)

Copy link
Contributor

Choose a reason for hiding this comment

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

Could we get a second opinion from another peer? @foolip maybe? I don't feel too strongly, just don't want us to get into trouble later.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ignoring extra attributes is the standard behavior of WebIDL, so that seems OK.

Copy link
Member

Choose a reason for hiding this comment

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

I think we should expect standards and tests to co-evolve, and that changing both is low friction, so I don't worry about the tests constraining changes. However, if an implementation did have an optional second string argument, this test wouldn't necessarily fail. Passing in { toString() { throw Error(); } } would catch it, but is there an object that will throw whatever the argument type is, including a dictionary? I suspect not.

If that can be solved generically, I think that something in idlharness.js might make sense. So, the value of this test probably isn't super high, and I would lean towards removing.

(Looking at this I noticed w3c/web-share#47)

Copy link
Contributor

Choose a reason for hiding this comment

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

If that can be solved generically, I think that something in idlharness.js might make sense.

This is what I would have suggested except afaik we don't have a good story for using idlharness on manual tests for now.

Copy link
Member Author

Choose a reason for hiding this comment

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

@foolip: Point taken, but I think your argument is that it won't necessarily catch implementations that are actually making use of a second argument (that's correct). I think there's still utility here, though, to catch implementations that throw an exception if they receive too many arguments.

Maybe the chance of that is low (since it's atypical for JavaScript code to care if there is excess arguments) but it's still a part of the IDL interface that's worth testing since it isn't (and can't be, for manual tests) tested by idlharness.

<script>
setup({explicit_timeout: true});

setupManualShareTest(false, '', '', '');
Copy link
Contributor

Choose a reason for hiding this comment

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

The pass expectation is unclear in this test.

Copy link
Member Author

Choose a reason for hiding this comment

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

See above.

// Sets up the page for running manual tests. Automatically creates the
// instructions (based on the parameters) and the share button.
function setupManualShareTest(
user_should_cancel, expected_title, expected_text, expected_url) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit, please move to previous line.

// instructions (based on the parameters) and the share button.
function setupManualShareTest(
user_should_cancel, expected_title, expected_text, expected_url) {
let div = document.createElement('div');
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: use "const" unless you are planning on reassigning the variable. Applies globally.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

setup({explicit_timeout: true});

setupManualShareTest(false, 'the title', 'the message', 'data:the url');
callWhenButtonClicked(() => navigator.share({title: 'the title', text: 'the message', url: 'data:the url', unused: 'unexpected field'}));
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: line length

@marcoscaceres
Copy link
Contributor

Few small things... with some of the tests, it's not totally clear what the pass condition is.

As an aside, I've been using https://github.com/prettier/prettier to format JS code for the Payments tests. It's be nice, but not mandatory, to format them tests using prettier.

idl_array.test();
}

promise_test(function() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe just:

        promise_test(async () => {
           const  response = await fetch('../interfaces/web-share.idl');
           doTest(await response.text());
         }, 'Test driver');

Copy link
Member Author

Choose a reason for hiding this comment

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

I'd love to do that (I write all my code in this style now) but I was afraid that some browsers don't support async/await yet and I don't want the tests to rely on that. Do you know if this is valid in all browsers we care about?

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

@@ -0,0 +1,71 @@
// Sets up the page for running manual tests. Automatically creates the
// instructions (based on the parameters) and the share button.
function setupManualShareTest(
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, let's change this to take an object, which you can then destructure.

function setupManualShareTest({ user_should_cancel,  expected_title,  expected_text, expected_url }) {

}

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't see a compelling need to do this, and it would make all the tests more verbose (having to explicitly say the name of each field whenever we call this).

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, but the alternative is to be a bit more clear with a comment when "setupManualShareTest" is called.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree with @marcoscaceres here, I had to go back and forth multiple times to figure out what each one represented. Would make reviewing much easier.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

@mgiuca
Copy link
Member Author

mgiuca commented Jun 22, 2017

As an aside, I've been using https://github.com/prettier/prettier to format JS code for the Payments tests. It's be nice, but not mandatory, to format them tests using prettier.

I tried this but it doesn't recognise HTML (prettier/prettier#1674). I don't think it's worthwhile manually extracting the JS and running this script, then putting it back.

I've addressed all the comments except some of the whitespace and formatting changes. I'm not really sure what to do about some of the line wrappings and I don't think it's worth spending time fussing about them. I've done a basic pass to avoid too-long lines, and all the formatting looks sensible to me. I agree it would be good if we just had an auto-formatter so we don't have to bikeshed about formatting but I don't know of any that works on HTML + JS. PTAL.

@marcoscaceres
Copy link
Contributor

I can live with formatting issues. As you said, eventually we can make a tool to tidy things up (e.g., via JSDom + Prettier or whatever).

{title: 'the title', text: 'the message', url: url}));
{title: 'the title', text: 'the message', url: url})).then(
result => {
// Check that promise resolved with undefined. This is guarded
Copy link
Member

Choose a reason for hiding this comment

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

Even with the comment I don't understand why the conditional helps. if result === undefined, then assert_equals(result, undefined) won't do anything visibly. I think this test is already relying on Tests.prototype.set_file_is_test in the end, so there is a test to fail even though it's implicit, right?

Copy link
Member Author

Choose a reason for hiding this comment

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

The structure of the manual tests is: if it fails in a detectable way, it should officially fail using the testharness framework, otherwise, it should neither visibly pass nor fail. It's just an ordinary web page with instructions for the user. The purpose of this is to avoid false positives.

When used in conjunction with tools/runner, the runner will ask the user whether it passed or failed, so this all makes sense.

The purpose of this if statement is that if the result is undefined, it does nothing (it's up to the user to determine whether it passed). But if the result is not undefined, it's fail because it did the wrong thing.

@foolip
Copy link
Member

foolip commented Jun 22, 2017

Left an additional nit, but this LGTM and I'll leave the rest to @marcoscaceres.

Copy link
Contributor

@marcoscaceres marcoscaceres left a comment

Choose a reason for hiding this comment

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

I'm traveling next few weeks, so marking as approved.

However, I'd like to see https://github.com/w3c/web-platform-tests/pull/6287/files#r123713014 addressed - and possibly the small refactor using async/await.

Also a huge thanks @mgiuca for the work he's put into this test suite!

@mgiuca
Copy link
Member Author

mgiuca commented Jun 27, 2017

I've done those changes. Note that the previous run failed on Safari 10.0 because "fetch" is not found (since someone asked me to change idlharness test to fetch the IDL file). It hasn't completed yet, but I think the next run will fail with a syntax error due to async/await.

According to Wikipedia and CanIUse, both of these features were added into Safari 10.1 which is now everywhere. So I think instead of removing these dependencies from the test, it's best to just land it and it will start working on Safari when the WPT bots update to Safari 10.1.

Re merging: Do I have to squash all the commits into a single commit or is it configured to do that automatically? I will wait until tomorrow to do this in case people want to compare history.

@tobie tobie merged commit 67406a4 into web-platform-tests:master Jun 27, 2017
@mgiuca
Copy link
Member Author

mgiuca commented Jun 27, 2017

Thanks!

@tobie tobie mentioned this pull request Jun 30, 2017
MXEBot pushed a commit to mirror/chromium that referenced this pull request Jul 1, 2017
The WPT (in external/wpt/web-share) contains manual tests for Web Share,
and Chrome has its own automated versions of those tests (using a mock
Mojo service). We can't delete the automated tests in favour of the
manual ones.

This CL applies a number of fixes to the layout tests to keep them in
sync with the upstream manual tests (these changes were made on the PR
to upstream the layout tests in the first place; see
web-platform-tests/wpt#6287).

- Adds test share-url-relative (tests document base URL).
- Use document.baseURI instead of location to calculate absolute URL.
- share-nonutf8-encoding: Assert that the document character encoding is
  as expected. Also changed iso-8859-1 to windows-1252 (canonical name).
- share-types: More robust tests of url field and object stringification.
- share-success: Check that promise is resolved with undefined.
- mock-share-service: Reject promise if an exception is thrown (fixes
  silent failure in share_tests when navigator.share is missing).

Bug: 730333
Change-Id: Ia27d149760af6b0494376c160da612ea2e947b8b
Reviewed-on: https://chromium-review.googlesource.com/554403
Commit-Queue: Matt Giuca <mgiuca@chromium.org>
Reviewed-by: Sam McNally <sammc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#483593}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants