mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
Introduce polymorphic page.waitFor method
This patch: - introduces page.waitForSelector to wait for the selector to appear - introduces polymorphic page.waitFor method, which accepts either string (and in this case is a shortcut for page.waitForSelector) or number (and in this case it's a promisified timeout). References #91.
This commit is contained in:
parent
1891a49962
commit
dc032b42b9
38
docs/api.md
38
docs/api.md
@ -59,8 +59,9 @@
|
|||||||
+ [page.url()](#pageurl)
|
+ [page.url()](#pageurl)
|
||||||
+ [page.userAgent()](#pageuseragent)
|
+ [page.userAgent()](#pageuseragent)
|
||||||
+ [page.viewport()](#pageviewport)
|
+ [page.viewport()](#pageviewport)
|
||||||
+ [page.waitFor(selector[, options])](#pagewaitforselector-options)
|
+ [page.waitFor(target[, options])](#pagewaitfortarget-options)
|
||||||
+ [page.waitForNavigation(options)](#pagewaitfornavigationoptions)
|
+ [page.waitForNavigation(options)](#pagewaitfornavigationoptions)
|
||||||
|
+ [page.waitForSelector(selector[, options])](#pagewaitforselectorselector-options)
|
||||||
* [class: Keyboard](#class-keyboard)
|
* [class: Keyboard](#class-keyboard)
|
||||||
+ [keyboard.down(key[, options])](#keyboarddownkey-options)
|
+ [keyboard.down(key[, options])](#keyboarddownkey-options)
|
||||||
+ [keyboard.modifiers()](#keyboardmodifiers)
|
+ [keyboard.modifiers()](#keyboardmodifiers)
|
||||||
@ -83,7 +84,8 @@
|
|||||||
+ [frame.name()](#framename)
|
+ [frame.name()](#framename)
|
||||||
+ [frame.parentFrame()](#frameparentframe)
|
+ [frame.parentFrame()](#frameparentframe)
|
||||||
+ [frame.url()](#frameurl)
|
+ [frame.url()](#frameurl)
|
||||||
+ [frame.waitFor(selector[, options])](#framewaitforselector-options)
|
+ [frame.waitFor(target[, options])](#framewaitfortarget-options)
|
||||||
|
+ [frame.waitForSelector(selector[, options])](#framewaitforselectorselector-options)
|
||||||
* [class: Request](#class-request)
|
* [class: Request](#class-request)
|
||||||
+ [request.headers](#requestheaders)
|
+ [request.headers](#requestheaders)
|
||||||
+ [request.method](#requestmethod)
|
+ [request.method](#requestmethod)
|
||||||
@ -592,18 +594,24 @@ This is a shortcut for [page.mainFrame().url()](#frameurl)
|
|||||||
#### page.viewport()
|
#### page.viewport()
|
||||||
- returns: <[Object]> An object with the save fields as described in [page.setViewport](#pagesetviewportviewport)
|
- returns: <[Object]> An object with the save fields as described in [page.setViewport](#pagesetviewportviewport)
|
||||||
|
|
||||||
|
#### page.waitFor(target[, options])
|
||||||
|
- `target` <[string]|[number]> A target to wait for.
|
||||||
|
- `options` <[Object]> Optional waiting parameters.
|
||||||
|
- returns: <[Promise]>
|
||||||
|
|
||||||
#### page.waitFor(selector[, options])
|
Shortcut for [page.mainFrame().waitFor()](#framewaitfortargetoptions).
|
||||||
- `selector` <[string]> A query selector to wait for on the page.
|
|
||||||
- `options` <[Object]> Optional waiting parameters. Same as options for the [frame.waitFor](#framewaitforselector)
|
|
||||||
- returns: <[Promise]> Promise which resolves when the element matching `selector` appears in the page.
|
|
||||||
|
|
||||||
Shortcut for [page.mainFrame().waitFor(selector)](#framewaitforselector).
|
|
||||||
|
|
||||||
#### page.waitForNavigation(options)
|
#### page.waitForNavigation(options)
|
||||||
- `options` <[Object]> Navigation parameters, same as in [page.navigate](#pagenavigateurl-options).
|
- `options` <[Object]> Navigation parameters, same as in [page.navigate](#pagenavigateurl-options).
|
||||||
- returns: <[Promise]<[Response]>> Promise which resolves to the main resource response. In case of multiple redirects, the navigation will resolve with the response of the last redirect.
|
- returns: <[Promise]<[Response]>> Promise which resolves to the main resource response. In case of multiple redirects, the navigation will resolve with the response of the last redirect.
|
||||||
|
|
||||||
|
#### page.waitForSelector(selector[, options])
|
||||||
|
- `selector` <[string]> A query selector to wait for on the page.
|
||||||
|
- `options` <[Object]> Optional waiting parameters. Same as options for the [frame.waitFor](#framewaitforselector)
|
||||||
|
- returns: <[Promise]> Promise which resolves when the element matching `selector` appears in the page.
|
||||||
|
|
||||||
|
Shortcut for [page.mainFrame().waitForSelector()](#framewaitforselectorselectoroptions).
|
||||||
|
|
||||||
### class: Keyboard
|
### class: Keyboard
|
||||||
|
|
||||||
Keyboard provides an api for managing a virtual keyboard. The high level api is [`keyboard.type`](#keyboardtypetext), which takes raw characters and generates proper keydown, keypress/input, and keyup events on your page.
|
Keyboard provides an api for managing a virtual keyboard. The high level api is [`keyboard.type`](#keyboardtypetext), which takes raw characters and generates proper keydown, keypress/input, and keyup events on your page.
|
||||||
@ -800,7 +808,17 @@ Returns frame's name as specified in the tag.
|
|||||||
|
|
||||||
Returns frame's url.
|
Returns frame's url.
|
||||||
|
|
||||||
#### frame.waitFor(selector[, options])
|
#### frame.waitFor(target[, options])
|
||||||
|
- `target` <[string]|[number]> A target to wait for
|
||||||
|
- `options` <[Object]> Optional waiting parameters
|
||||||
|
- returns: <[Promise]>
|
||||||
|
|
||||||
|
This method behaves differently wrt the type of the first parameter:
|
||||||
|
- if `target` is a `string`, than target is treated as a selector to wait for and the method is a shortcut for [frame.waitForSelector](#framewaitforselectorselectoroptions)
|
||||||
|
- if `target` is a `number`, than target is treated as timeout in milliseconds and the method returns a promise which resolves after the timeout
|
||||||
|
- otherwise, an exception is thrown
|
||||||
|
|
||||||
|
#### frame.waitForSelector(selector[, options])
|
||||||
- `selector` <[string]> CSS selector of awaited element,
|
- `selector` <[string]> CSS selector of awaited element,
|
||||||
- `options` <[Object]> Optional waiting parameters
|
- `options` <[Object]> Optional waiting parameters
|
||||||
- `visible` <[boolean]> wait for element to be present in DOM and to be visible, i.e. to not have `display: none` or `visibility: hidden` CSS properties. Defaults to `false`.
|
- `visible` <[boolean]> wait for element to be present in DOM and to be visible, i.e. to not have `display: none` or `visibility: hidden` CSS properties. Defaults to `false`.
|
||||||
@ -818,7 +836,7 @@ const browser = new Browser();
|
|||||||
|
|
||||||
browser.newPage().then(async page => {
|
browser.newPage().then(async page => {
|
||||||
let currentURL;
|
let currentURL;
|
||||||
page.waitFor('img').then(() => console.log('First URL with image: ' + currentURL));
|
page.waitForSelector('img').then(() => console.log('First URL with image: ' + currentURL));
|
||||||
for (currentURL of ['https://example.com', 'https://google.com', 'https://bbc.com'])
|
for (currentURL of ['https://example.com', 'https://google.com', 'https://bbc.com'])
|
||||||
await page.navigate(currentURL);
|
await page.navigate(currentURL);
|
||||||
browser.close();
|
browser.close();
|
||||||
|
@ -201,7 +201,7 @@ class FrameManager extends EventEmitter {
|
|||||||
async function inPageWatchdog(selector, visible, timeout) {
|
async function inPageWatchdog(selector, visible, timeout) {
|
||||||
const resultPromise = visible ? waitForVisible(selector) : waitInDOM(selector);
|
const resultPromise = visible ? waitForVisible(selector) : waitInDOM(selector);
|
||||||
const timeoutPromise = new Promise((resolve, reject) => {
|
const timeoutPromise = new Promise((resolve, reject) => {
|
||||||
setTimeout(reject.bind(null, new Error(`waitFor failed: timeout ${timeout}ms exceeded.`)), timeout);
|
setTimeout(reject.bind(null, new Error(`waitForSelector failed: timeout ${timeout}ms exceeded.`)), timeout);
|
||||||
});
|
});
|
||||||
await Promise.race([resultPromise, timeoutPromise]);
|
await Promise.race([resultPromise, timeoutPromise]);
|
||||||
|
|
||||||
@ -342,17 +342,30 @@ class Frame {
|
|||||||
return this._detached;
|
return this._detached;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {(string|number)} target
|
||||||
|
* @param {!Object=} options
|
||||||
|
* @return {!Promise}
|
||||||
|
*/
|
||||||
|
waitFor(target, options = {}) {
|
||||||
|
if (typeof target === 'string' || target instanceof String)
|
||||||
|
return this.waitForSelector(target, options);
|
||||||
|
if (typeof target === 'number' || target instanceof Number)
|
||||||
|
return new Promise(fulfill => setTimeout(fulfill, target));
|
||||||
|
return Promise.reject(new Error('Unsupported target type: ' + (typeof target)));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} selector
|
* @param {string} selector
|
||||||
* @param {!Object=} options
|
* @param {!Object=} options
|
||||||
* @return {!Promise}
|
* @return {!Promise}
|
||||||
*/
|
*/
|
||||||
async waitFor(selector, options = {}) {
|
waitForSelector(selector, options = {}) {
|
||||||
const timeout = options.timeout || 30000;
|
const timeout = options.timeout || 30000;
|
||||||
const awaitedElement = new AwaitedElement(() => this._frameManager._waitForSelector(this, selector, !!options.visible, timeout));
|
const awaitedElement = new AwaitedElement(() => this._frameManager._waitForSelector(this, selector, !!options.visible, timeout));
|
||||||
// Since navigation will re-install page watchdogs, we should timeout on our
|
// Since navigation will re-install page watchdogs, we should timeout on our
|
||||||
// end as well.
|
// end as well.
|
||||||
setTimeout(() => awaitedElement.terminate(new Error(`waitFor failed: timeout ${timeout}ms exceeded`)), timeout);
|
setTimeout(() => awaitedElement.terminate(new Error(`waitForSelector failed: timeout ${timeout}ms exceeded`)), timeout);
|
||||||
|
|
||||||
this._awaitedElements.add(awaitedElement);
|
this._awaitedElements.add(awaitedElement);
|
||||||
let cleanup = () => this._awaitedElements.delete(awaitedElement);
|
let cleanup = () => this._awaitedElements.delete(awaitedElement);
|
||||||
|
15
lib/Page.js
15
lib/Page.js
@ -597,12 +597,21 @@ class Page extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} selector
|
* @param {string} target
|
||||||
* @param {!Object=} options
|
* @param {!Object=} options
|
||||||
* @return {!Promise<undefined>}
|
* @return {!Promise<undefined>}
|
||||||
*/
|
*/
|
||||||
waitFor(selector, options) {
|
waitFor(target, options) {
|
||||||
return this.mainFrame().waitFor(selector, options);
|
return this.mainFrame().waitFor(target, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} selector
|
||||||
|
* @param {!Object=} options
|
||||||
|
* @return {!Promise}
|
||||||
|
*/
|
||||||
|
waitForSelector(selector, options = {}) {
|
||||||
|
return this.mainFrame().waitForSelector(selector, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
62
test/test.js
62
test/test.js
@ -162,7 +162,7 @@ describe('Puppeteer', function() {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Frame.waitFor', function() {
|
describe('Frame.waitForSelector', function() {
|
||||||
let FrameUtils = require('./frame-utils');
|
let FrameUtils = require('./frame-utils');
|
||||||
let addElement = tag => document.body.appendChild(document.createElement(tag));
|
let addElement = tag => document.body.appendChild(document.createElement(tag));
|
||||||
|
|
||||||
@ -170,12 +170,12 @@ describe('Puppeteer', function() {
|
|||||||
await page.navigate(EMPTY_PAGE);
|
await page.navigate(EMPTY_PAGE);
|
||||||
let frame = page.mainFrame();
|
let frame = page.mainFrame();
|
||||||
let added = false;
|
let added = false;
|
||||||
await frame.waitFor('*').then(() => added = true);
|
await frame.waitForSelector('*').then(() => added = true);
|
||||||
expect(added).toBe(true);
|
expect(added).toBe(true);
|
||||||
|
|
||||||
added = false;
|
added = false;
|
||||||
await frame.evaluate(addElement, 'div');
|
await frame.evaluate(addElement, 'div');
|
||||||
await frame.waitFor('div').then(() => added = true);
|
await frame.waitForSelector('div').then(() => added = true);
|
||||||
expect(added).toBe(true);
|
expect(added).toBe(true);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -183,10 +183,10 @@ describe('Puppeteer', function() {
|
|||||||
await page.navigate(EMPTY_PAGE);
|
await page.navigate(EMPTY_PAGE);
|
||||||
let frame = page.mainFrame();
|
let frame = page.mainFrame();
|
||||||
let added = false;
|
let added = false;
|
||||||
frame.waitFor('div').then(() => added = true);
|
frame.waitForSelector('div').then(() => added = true);
|
||||||
// run nop function..
|
// run nop function..
|
||||||
await frame.evaluate(() => 42);
|
await frame.evaluate(() => 42);
|
||||||
// .. to be sure that waitFor promise is not resolved yet.
|
// .. to be sure that waitForSelector promise is not resolved yet.
|
||||||
expect(added).toBe(false);
|
expect(added).toBe(false);
|
||||||
await frame.evaluate(addElement, 'br');
|
await frame.evaluate(addElement, 'br');
|
||||||
expect(added).toBe(false);
|
expect(added).toBe(false);
|
||||||
@ -198,19 +198,19 @@ describe('Puppeteer', function() {
|
|||||||
await page.navigate(EMPTY_PAGE);
|
await page.navigate(EMPTY_PAGE);
|
||||||
let frame = page.mainFrame();
|
let frame = page.mainFrame();
|
||||||
let added = false;
|
let added = false;
|
||||||
frame.waitFor('h3 div').then(() => added = true);
|
frame.waitForSelector('h3 div').then(() => added = true);
|
||||||
expect(added).toBe(false);
|
expect(added).toBe(false);
|
||||||
await frame.evaluate(addElement, 'span');
|
await frame.evaluate(addElement, 'span');
|
||||||
await page.$('span', span => span.innerHTML = '<h3><div></div></h3>');
|
await page.$('span', span => span.innerHTML = '<h3><div></div></h3>');
|
||||||
expect(added).toBe(true);
|
expect(added).toBe(true);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('Page.waitFor is shortcut for main frame', SX(async function() {
|
it('Page.waitForSelector is shortcut for main frame', SX(async function() {
|
||||||
await page.navigate(EMPTY_PAGE);
|
await page.navigate(EMPTY_PAGE);
|
||||||
await FrameUtils.attachFrame(page, 'frame1', EMPTY_PAGE);
|
await FrameUtils.attachFrame(page, 'frame1', EMPTY_PAGE);
|
||||||
let otherFrame = page.frames()[1];
|
let otherFrame = page.frames()[1];
|
||||||
let added = false;
|
let added = false;
|
||||||
page.waitFor('div').then(() => added = true);
|
page.waitForSelector('div').then(() => added = true);
|
||||||
await otherFrame.evaluate(addElement, 'div');
|
await otherFrame.evaluate(addElement, 'div');
|
||||||
expect(added).toBe(false);
|
expect(added).toBe(false);
|
||||||
await page.evaluate(addElement, 'div');
|
await page.evaluate(addElement, 'div');
|
||||||
@ -223,7 +223,7 @@ describe('Puppeteer', function() {
|
|||||||
let frame1 = page.frames()[1];
|
let frame1 = page.frames()[1];
|
||||||
let frame2 = page.frames()[2];
|
let frame2 = page.frames()[2];
|
||||||
let added = false;
|
let added = false;
|
||||||
frame2.waitFor('div').then(() => added = true);
|
frame2.waitForSelector('div').then(() => added = true);
|
||||||
expect(added).toBe(false);
|
expect(added).toBe(false);
|
||||||
await frame1.evaluate(addElement, 'div');
|
await frame1.evaluate(addElement, 'div');
|
||||||
expect(added).toBe(false);
|
expect(added).toBe(false);
|
||||||
@ -237,8 +237,8 @@ describe('Puppeteer', function() {
|
|||||||
});
|
});
|
||||||
await page.navigate(EMPTY_PAGE);
|
await page.navigate(EMPTY_PAGE);
|
||||||
try {
|
try {
|
||||||
await page.waitFor('*');
|
await page.waitForSelector('*');
|
||||||
fail('Failed waitFor did not throw.');
|
fail('Failed waitForSelector did not throw.');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
expect(e.message).toContain('document.querySelector is not a function');
|
expect(e.message).toContain('document.querySelector is not a function');
|
||||||
}
|
}
|
||||||
@ -247,7 +247,7 @@ describe('Puppeteer', function() {
|
|||||||
await FrameUtils.attachFrame(page, 'frame1', EMPTY_PAGE);
|
await FrameUtils.attachFrame(page, 'frame1', EMPTY_PAGE);
|
||||||
let frame = page.frames()[1];
|
let frame = page.frames()[1];
|
||||||
let waitError = null;
|
let waitError = null;
|
||||||
let waitPromise = frame.waitFor('.box').catch(e => waitError = e);
|
let waitPromise = frame.waitForSelector('.box').catch(e => waitError = e);
|
||||||
await FrameUtils.detachFrame(page, 'frame1');
|
await FrameUtils.detachFrame(page, 'frame1');
|
||||||
await waitPromise;
|
await waitPromise;
|
||||||
expect(waitError).toBeTruthy();
|
expect(waitError).toBeTruthy();
|
||||||
@ -255,30 +255,56 @@ describe('Puppeteer', function() {
|
|||||||
}));
|
}));
|
||||||
it('should survive navigation', SX(async function() {
|
it('should survive navigation', SX(async function() {
|
||||||
let boxFound = false;
|
let boxFound = false;
|
||||||
let waitFor = page.waitFor('.box').then(() => boxFound = true);
|
let waitForSelector = page.waitForSelector('.box').then(() => boxFound = true);
|
||||||
await page.navigate(EMPTY_PAGE);
|
await page.navigate(EMPTY_PAGE);
|
||||||
expect(boxFound).toBe(false);
|
expect(boxFound).toBe(false);
|
||||||
await page.reload();
|
await page.reload();
|
||||||
expect(boxFound).toBe(false);
|
expect(boxFound).toBe(false);
|
||||||
await page.navigate(PREFIX + '/grid.html');
|
await page.navigate(PREFIX + '/grid.html');
|
||||||
await waitFor;
|
await waitForSelector;
|
||||||
expect(boxFound).toBe(true);
|
expect(boxFound).toBe(true);
|
||||||
}));
|
}));
|
||||||
it('should wait for visible', SX(async function() {
|
it('should wait for visible', SX(async function() {
|
||||||
let divFound = false;
|
let divFound = false;
|
||||||
let waitFor = page.waitFor('div', {visible: true}).then(() => divFound = true);
|
let waitForSelector = page.waitForSelector('div', {visible: true}).then(() => divFound = true);
|
||||||
await page.setContent(`<div style='display: none;visibility: hidden'></div>`);
|
await page.setContent(`<div style='display: none;visibility: hidden'></div>`);
|
||||||
expect(divFound).toBe(false);
|
expect(divFound).toBe(false);
|
||||||
await page.evaluate(() => document.querySelector('div').style.removeProperty('display'));
|
await page.evaluate(() => document.querySelector('div').style.removeProperty('display'));
|
||||||
expect(divFound).toBe(false);
|
expect(divFound).toBe(false);
|
||||||
await page.evaluate(() => document.querySelector('div').style.removeProperty('visibility'));
|
await page.evaluate(() => document.querySelector('div').style.removeProperty('visibility'));
|
||||||
expect(await waitFor).toBe(true);
|
expect(await waitForSelector).toBe(true);
|
||||||
}));
|
}));
|
||||||
it('should respect timeout', SX(async function() {
|
it('should respect timeout', SX(async function() {
|
||||||
let error = null;
|
let error = null;
|
||||||
await page.waitFor('div', {timeout: 10}).catch(e => error = e);
|
await page.waitForSelector('div', {timeout: 10}).catch(e => error = e);
|
||||||
expect(error).toBeTruthy();
|
expect(error).toBeTruthy();
|
||||||
expect(error.message).toContain('waitFor failed: timeout');
|
expect(error.message).toContain('waitForSelector failed: timeout');
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Page.waitFor', function() {
|
||||||
|
it('should wait for selector', SX(async function() {
|
||||||
|
let found = false;
|
||||||
|
let waitFor = page.waitFor('div').then(() => found = true);
|
||||||
|
await page.navigate(EMPTY_PAGE);
|
||||||
|
expect(found).toBe(false);
|
||||||
|
await page.navigate(PREFIX + '/grid.html');
|
||||||
|
await waitFor;
|
||||||
|
expect(found).toBe(true);
|
||||||
|
}));
|
||||||
|
it('should timeout', SX(async function() {
|
||||||
|
startTime = Date.now();
|
||||||
|
const timeout = 42;
|
||||||
|
await page.waitFor(timeout);
|
||||||
|
expect(Date.now() - startTime).not.toBeLessThan(timeout);
|
||||||
|
}));
|
||||||
|
it('should throw when unknown type', SX(async function() {
|
||||||
|
try {
|
||||||
|
await page.waitFor({foo: 'bar'});
|
||||||
|
fail('Failed to throw exception');
|
||||||
|
} catch (e) {
|
||||||
|
expect(e.message).toContain('Unsupported target type');
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -94,10 +94,13 @@ function lintMarkdown(doc) {
|
|||||||
if (member1.type === 'method' && member1.name === 'constructor')
|
if (member1.type === 'method' && member1.name === 'constructor')
|
||||||
continue;
|
continue;
|
||||||
if (member1.name > member2.name) {
|
if (member1.name > member2.name) {
|
||||||
let memberName = `${cls.name}.${member1.name}`;
|
let memberName1 = `${cls.name}.${member1.name}`;
|
||||||
if (member1.type === 'method')
|
if (member1.type === 'method')
|
||||||
memberName += '()';
|
memberName1 += '()';
|
||||||
errors.push(`${memberName} breaks alphabetic ordering of class members.`);
|
let memberName2 = `${cls.name}.${member2.name}`;
|
||||||
|
if (member2.type === 'method')
|
||||||
|
memberName2 += '()';
|
||||||
|
errors.push(`Bad alphabetic ordering of ${cls.name} members: ${memberName1} should go after ${memberName2}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[MarkDown] Events should go first. Event 'b' in class Foo breaks order
|
[MarkDown] Events should go first. Event 'b' in class Foo breaks order
|
||||||
[MarkDown] Constructor of Foo should go before other methods
|
[MarkDown] Constructor of Foo should go before other methods
|
||||||
[MarkDown] Event 'c' in class Foo breaks alphabetic ordering of events
|
[MarkDown] Event 'c' in class Foo breaks alphabetic ordering of events
|
||||||
[MarkDown] Foo.ddd breaks alphabetic ordering of class members.
|
[MarkDown] Bad alphabetic ordering of Foo members: Foo.ddd should go after Foo.constructor()
|
||||||
[MarkDown] Foo.ccc() breaks alphabetic ordering of class members.
|
[MarkDown] Bad alphabetic ordering of Foo members: Foo.ccc() should go after Foo.bbb()
|
Loading…
Reference in New Issue
Block a user