mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-11 11:15:24 +03:00
Merge branch 'master' into rebrand-and-bump-electron-to-12
This commit is contained in:
commit
24ef5a1a05
@ -62,7 +62,6 @@
|
||||
| [Line Ending Selector](https://github.com/atom/atom/tree/master/packages/line-ending-selector) | | [![Dependency Status](https://david-dm.org/atom/line-ending-selector.svg)](https://david-dm.org/atom/line-ending-selector) |
|
||||
| [Link](https://github.com/atom/atom/tree/master/packages/link) | | [![Dependency Status](https://david-dm.org/atom/link.svg)](https://david-dm.org/atom/link) |
|
||||
| [Markdown Preview](https://github.com/atom/markdown-preview) | [![build](https://github.com/atom/markdown-preview/workflows/CI/badge.svg)](https://github.com/atom/markdown-preview/actions) | [![Dependency Status](https://david-dm.org/atom/markdown-preview.svg)](https://david-dm.org/atom/markdown-preview) |
|
||||
| [Metrics](https://github.com/atom/metrics) | [![build](https://github.com/atom/metrics/workflows/CI/badge.svg)](https://github.com/atom/metrics/actions) | [![Dependency Status](https://david-dm.org/atom/metrics.svg)](https://david-dm.org/atom/metrics) |
|
||||
| [Notifications](https://github.com/atom/notifications) | [![build](https://github.com/atom/notifications/workflows/CI/badge.svg)](https://github.com/atom/notifications/actions) | [![Dependency Status](https://david-dm.org/atom/notifications.svg)](https://david-dm.org/atom/notifications) |
|
||||
| [Open on GitHub](https://github.com/atom/open-on-github) | [![build](https://github.com/atom/open-on-github/workflows/CI/badge.svg)](https://github.com/atom/open-on-github/actions) | [![Dependency Status](https://david-dm.org/atom/open-on-github.svg)](https://david-dm.org/atom/open-on-github) |
|
||||
| [Package Generator](https://github.com/atom/package-generator) | [![build](https://github.com/atom/package-generator/workflows/CI/badge.svg)](https://github.com/atom/package-generator/actions) | [![Dependency Status](https://david-dm.org/atom/package-generator.svg)](https://david-dm.org/atom/package-generator) |
|
||||
|
36
package-lock.json
generated
36
package-lock.json
generated
@ -8154,25 +8154,6 @@
|
||||
"is-buffer": "~1.1.6"
|
||||
}
|
||||
},
|
||||
"metrics": {
|
||||
"version": "https://www.atom.io/api/packages/metrics/versions/1.8.1/tarball",
|
||||
"integrity": "sha512-3yMZVI3eOixkeVORM0psQ1Hr7aooLBBwNGgIrIo59SQytLorj/7VYLCTaaYW1hup5m3fcU8vKlrGBj+UNfGJbA==",
|
||||
"requires": {
|
||||
"fs-plus": "^3.0.0",
|
||||
"grim": "^2.0.1",
|
||||
"telemetry-github": "0.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"grim": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/grim/-/grim-2.0.2.tgz",
|
||||
"integrity": "sha512-Qj7hTJRfd87E/gUgfvM0YIH/g2UA2SV6niv6BYXk1o6w4mhgv+QyYM1EjOJQljvzgEj4SqSsRWldXIeKHz3e3Q==",
|
||||
"requires": {
|
||||
"event-kit": "^2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
@ -10471,23 +10452,6 @@
|
||||
"xtend": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"telemetry-github": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/telemetry-github/-/telemetry-github-0.1.1.tgz",
|
||||
"integrity": "sha512-UUtkNKKHpUthL4FsAJDqKg+TiW0DBI636XAOAA3qcu86m20DhLhn3qhxl12joGdPBtk0tbv/Dx47pj28ZhuF+g==",
|
||||
"requires": {
|
||||
"idb": "^4.0.3",
|
||||
"lokijs": "^1.5.4",
|
||||
"uuid": "^3.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
|
||||
"integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"temp": {
|
||||
"version": "0.9.2",
|
||||
"resolved": "https://registry.npmjs.org/temp/-/temp-0.9.2.tgz",
|
||||
|
@ -128,7 +128,6 @@
|
||||
"line-top-index": "0.3.1",
|
||||
"link": "file:packages/link",
|
||||
"markdown-preview": "https://codeload.github.com/atom/markdown-preview/legacy.tar.gz/refs/tags/v0.160.2",
|
||||
"metrics": "https://codeload.github.com/atom/metrics/legacy.tar.gz/refs/tags/v1.8.1",
|
||||
"minimatch": "^3.0.3",
|
||||
"mocha": "6.2.3",
|
||||
"mocha-junit-reporter": "2.0.0",
|
||||
@ -224,7 +223,6 @@
|
||||
"line-ending-selector": "file:./packages/line-ending-selector",
|
||||
"link": "file:./packages/link",
|
||||
"markdown-preview": "0.160.2",
|
||||
"metrics": "1.8.1",
|
||||
"notifications": "0.72.1",
|
||||
"open-on-github": "1.3.2",
|
||||
"package-generator": "1.3.0",
|
||||
|
@ -77,7 +77,6 @@ See [RFC 003](https://github.com/atom/atom/blob/master/docs/rfcs/003-consolidate
|
||||
| **line-ending-selector** | [`./packages/line-ending-selector`](./line-ending-selector) | [#17847](https://github.com/atom/atom/issues/17847) |
|
||||
| **link** | [`./link`](./link) | [#17848](https://github.com/atom/atom/issues/17848) |
|
||||
| **markdown-preview** | [`atom/markdown-preview`][markdown-preview] | |
|
||||
| **metrics** | [`atom/metrics`][metrics] | [#18276](https://github.com/atom/atom/issues/18276) |
|
||||
| **notifications** | [`atom/notifications`][notifications] | [#18277](https://github.com/atom/atom/issues/18277) |
|
||||
| **one-dark-syntax** | [`./one-dark-syntax`](./one-dark-syntax) | [#17853](https://github.com/atom/atom/issues/17853) |
|
||||
| **one-dark-ui** | [`./one-dark-ui`](./one-dark-ui) | [#17854](https://github.com/atom/atom/issues/17854) |
|
||||
@ -152,7 +151,6 @@ See [RFC 003](https://github.com/atom/atom/blob/master/docs/rfcs/003-consolidate
|
||||
[language-xml]: https://github.com/atom/language-xml
|
||||
[language-yaml]: https://github.com/atom/language-yaml
|
||||
[markdown-preview]: https://github.com/atom/markdown-preview
|
||||
[metrics]: https://github.com/atom/metrics
|
||||
[notifications]: https://github.com/atom/notifications
|
||||
[open-on-github]: https://github.com/atom/open-on-github
|
||||
[package-generator]: https://github.com/atom/package-generator
|
||||
|
@ -120,16 +120,10 @@ export default class Reporter {
|
||||
}
|
||||
|
||||
shouldReport(error) {
|
||||
if (this.alwaysReport) return true; // Used in specs
|
||||
if (atom.config.get('core.telemetryConsent') !== 'limited') return false;
|
||||
if (atom.inDevMode()) return false;
|
||||
|
||||
const topFrame = this.parseStackTrace(error)[0];
|
||||
const fileName = topFrame ? topFrame.getFileName() : null;
|
||||
return (
|
||||
fileName &&
|
||||
(this.isBundledFile(fileName) || this.isTeletypeFile(fileName))
|
||||
);
|
||||
// Since the `core.telemetryConsent` variable has been removed, this has no good way
|
||||
// to check if should report to the remote. So we will just always return false
|
||||
// to report to remote. But still allow reporting locally.
|
||||
return false;
|
||||
}
|
||||
|
||||
parseStackTrace(error) {
|
||||
|
@ -1,3 +1,3 @@
|
||||
## Welcome package
|
||||
|
||||
Opens a welcome editor with helpful information the very first time Atom is opened and the usage statistics opt-in.
|
||||
Opens a welcome editor with helpful information the very first time Atom is opened.
|
||||
|
@ -1,151 +0,0 @@
|
||||
'use babel';
|
||||
/** @jsx etch.dom */
|
||||
|
||||
import etch from 'etch';
|
||||
|
||||
export default class ConsentView {
|
||||
constructor() {
|
||||
etch.initialize(this);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="welcome">
|
||||
<div className="welcome-container">
|
||||
<div className="header">
|
||||
<a title="atom.io" href="https://atom.io/">
|
||||
<svg
|
||||
class="welcome-logo"
|
||||
width="330px"
|
||||
height="68px"
|
||||
viewBox="0 0 330 68"
|
||||
version="1.1"
|
||||
>
|
||||
<g
|
||||
stroke="none"
|
||||
stroke-width="1"
|
||||
fill="none"
|
||||
fill-rule="evenodd"
|
||||
>
|
||||
<g transform="translate(2.000000, 1.000000)">
|
||||
<g
|
||||
transform="translate(96.000000, 8.000000)"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path d="M185.498,3.399 C185.498,2.417 186.34,1.573 187.324,1.573 L187.674,1.573 C188.447,1.573 189.01,1.995 189.5,2.628 L208.676,30.862 L227.852,2.628 C228.272,1.995 228.905,1.573 229.676,1.573 L230.028,1.573 C231.01,1.573 231.854,2.417 231.854,3.399 L231.854,49.403 C231.854,50.387 231.01,51.231 230.028,51.231 C229.044,51.231 228.202,50.387 228.202,49.403 L228.202,8.246 L210.151,34.515 C209.729,35.148 209.237,35.428 208.606,35.428 C207.973,35.428 207.481,35.148 207.061,34.515 L189.01,8.246 L189.01,49.475 C189.01,50.457 188.237,51.231 187.254,51.231 C186.27,51.231 185.498,50.458 185.498,49.475 L185.498,3.399 L185.498,3.399 Z" />
|
||||
<path d="M113.086,26.507 L113.086,26.367 C113.086,12.952 122.99,0.941 137.881,0.941 C152.77,0.941 162.533,12.811 162.533,26.225 L162.533,26.367 C162.533,39.782 152.629,51.792 137.74,51.792 C122.85,51.792 113.086,39.923 113.086,26.507 M158.74,26.507 L158.74,26.367 C158.74,14.216 149.89,4.242 137.74,4.242 C125.588,4.242 116.879,14.075 116.879,26.225 L116.879,26.367 C116.879,38.518 125.729,48.491 137.881,48.491 C150.031,48.491 158.74,38.658 158.74,26.507" />
|
||||
<path d="M76.705,5.155 L60.972,5.155 C60.06,5.155 59.287,4.384 59.287,3.469 C59.287,2.556 60.059,1.783 60.972,1.783 L96.092,1.783 C97.004,1.783 97.778,2.555 97.778,3.469 C97.778,4.383 97.005,5.155 96.092,5.155 L80.358,5.155 L80.358,49.405 C80.358,50.387 79.516,51.231 78.532,51.231 C77.55,51.231 76.706,50.387 76.706,49.405 L76.706,5.155 L76.705,5.155 Z" />
|
||||
<path d="M0.291,48.562 L21.291,3.05 C21.783,1.995 22.485,1.292 23.75,1.292 L23.891,1.292 C25.155,1.292 25.858,1.995 26.348,3.05 L47.279,48.421 C47.49,48.843 47.56,49.194 47.56,49.546 C47.56,50.458 46.788,51.231 45.803,51.231 C44.961,51.231 44.329,50.599 43.978,49.826 L38.219,37.183 L9.21,37.183 L3.45,49.897 C3.099,50.739 2.538,51.231 1.694,51.231 C0.781,51.231 0.008,50.529 0.008,49.685 C0.009,49.404 0.08,48.983 0.291,48.562 L0.291,48.562 Z M36.673,33.882 L23.749,5.437 L10.755,33.882 L36.673,33.882 L36.673,33.882 Z" />
|
||||
</g>
|
||||
<g>
|
||||
<path
|
||||
d="M40.363,32.075 C40.874,34.44 39.371,36.77 37.006,37.282 C34.641,37.793 32.311,36.29 31.799,33.925 C31.289,31.56 32.791,29.23 35.156,28.718 C37.521,28.207 39.851,29.71 40.363,32.075"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M48.578,28.615 C56.851,45.587 58.558,61.581 52.288,64.778 C45.822,68.076 33.326,56.521 24.375,38.969 C15.424,21.418 13.409,4.518 19.874,1.221 C22.689,-0.216 26.648,1.166 30.959,4.629"
|
||||
stroke="currentColor"
|
||||
stroke-width="3.08"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M7.64,39.45 C2.806,36.94 -0.009,33.915 0.154,30.79 C0.531,23.542 16.787,18.497 36.462,19.52 C56.137,20.544 71.781,27.249 71.404,34.497 C71.241,37.622 68.127,40.338 63.06,42.333"
|
||||
stroke="currentColor"
|
||||
stroke-width="3.08"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M28.828,59.354 C23.545,63.168 18.843,64.561 15.902,62.653 C9.814,58.702 13.572,42.102 24.296,25.575 C35.02,9.048 48.649,-1.149 54.736,2.803 C57.566,4.639 58.269,9.208 57.133,15.232"
|
||||
stroke="currentColor"
|
||||
stroke-width="3.08"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<div className="welcome-consent">
|
||||
<p>
|
||||
<strong>This functionality is planning to be removed.</strong>
|
||||
Help improve {atom.branding.name} by sending your anonymous{' '}
|
||||
<strong>usage data</strong> to the {atom.branding.name} team. The resulting data
|
||||
plays a key role in deciding what we focus on next.
|
||||
</p>
|
||||
|
||||
<div className="welcome-consent-choices">
|
||||
<div>
|
||||
<button
|
||||
className="btn btn-primary"
|
||||
onclick={this.consent.bind(this)}
|
||||
>
|
||||
Yes, send my usage data
|
||||
</button>
|
||||
<p className="welcome-note">
|
||||
Including exception and crash reports. See the{' '}
|
||||
<a onclick={this.openMetricsPackage.bind(this)}>
|
||||
atom/metrics package
|
||||
</a>{' '}
|
||||
for more details.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button
|
||||
className="btn btn-primary"
|
||||
onclick={this.decline.bind(this)}
|
||||
>
|
||||
No, do not send my usage data
|
||||
</button>
|
||||
<p className="welcome-note">
|
||||
Note: We only register anonymously that you opted-out.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="welcome-footer">
|
||||
<p className="welcome-love">
|
||||
<span className="icon icon-code" />
|
||||
<span className="inline"> with </span>
|
||||
<span className="icon icon-heart" />
|
||||
<span className="inline"> by </span>
|
||||
<a
|
||||
className="icon icon-logo-github"
|
||||
title="GitHub"
|
||||
href="https://github.com"
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
update() {
|
||||
return etch.update(this);
|
||||
}
|
||||
|
||||
consent() {
|
||||
atom.config.set('core.telemetryConsent', 'limited');
|
||||
atom.workspace.closeActivePaneItemOrEmptyPaneOrWindow();
|
||||
}
|
||||
|
||||
decline() {
|
||||
atom.config.set('core.telemetryConsent', 'no');
|
||||
atom.workspace.closeActivePaneItemOrEmptyPaneOrWindow();
|
||||
}
|
||||
|
||||
openMetricsPackage() {
|
||||
atom.workspace.open('atom://config/packages/metrics');
|
||||
}
|
||||
|
||||
getTitle() {
|
||||
return 'Telemetry Consent';
|
||||
}
|
||||
|
||||
async destroy() {
|
||||
await etch.destroy(this);
|
||||
}
|
||||
}
|
@ -3,11 +3,10 @@
|
||||
import { CompositeDisposable } from 'atom';
|
||||
import ReporterProxy from './reporter-proxy';
|
||||
|
||||
let WelcomeView, GuideView, ConsentView;
|
||||
let WelcomeView, GuideView;
|
||||
|
||||
const WELCOME_URI = 'atom://welcome/welcome';
|
||||
const GUIDE_URI = 'atom://welcome/guide';
|
||||
const CONSENT_URI = 'atom://welcome/consent';
|
||||
|
||||
export default class WelcomePackage {
|
||||
constructor() {
|
||||
@ -33,22 +32,10 @@ export default class WelcomePackage {
|
||||
})
|
||||
);
|
||||
|
||||
this.subscriptions.add(
|
||||
atom.workspace.addOpener(filePath => {
|
||||
if (filePath === CONSENT_URI) {
|
||||
return this.createConsentView({ uri: CONSENT_URI });
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
this.subscriptions.add(
|
||||
atom.commands.add('atom-workspace', 'welcome:show', () => this.show())
|
||||
);
|
||||
|
||||
if (atom.config.get('core.telemetryConsent') === 'undecided') {
|
||||
await atom.workspace.open(CONSENT_URI);
|
||||
}
|
||||
|
||||
if (atom.config.get('welcome.showOnStartup')) {
|
||||
await this.show();
|
||||
this.reporterProxy.sendEvent('show-on-initial-load');
|
||||
@ -79,9 +66,4 @@ export default class WelcomePackage {
|
||||
if (GuideView == null) GuideView = require('./guide-view');
|
||||
return new GuideView({ reporterProxy: this.reporterProxy, ...state });
|
||||
}
|
||||
|
||||
createConsentView(state) {
|
||||
if (ConsentView == null) ConsentView = require('./consent-view');
|
||||
return new ConsentView({ reporterProxy: this.reporterProxy, ...state });
|
||||
}
|
||||
}
|
||||
|
@ -14,11 +14,7 @@
|
||||
"test": "atom --test test/*.test.js"
|
||||
},
|
||||
"consumedServices": {
|
||||
"metrics-reporter": {
|
||||
"versions": {
|
||||
"^1.1.0": "consumeReporter"
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
"configSchema": {
|
||||
"showOnStartup": {
|
||||
|
@ -17,24 +17,21 @@ describe('Welcome', () => {
|
||||
atom.reset();
|
||||
});
|
||||
|
||||
describe("when `core.telemetryConsent` is 'undecided'", () => {
|
||||
describe("when welcomePackage.activate is called", () => {
|
||||
beforeEach(async () => {
|
||||
atom.config.set('core.telemetryConsent', 'undecided');
|
||||
await welcomePackage.activate();
|
||||
});
|
||||
|
||||
it('opens the telemetry consent pane and the welcome panes', () => {
|
||||
it('opens the welcome panes', () => {
|
||||
const panes = atom.workspace.getCenter().getPanes();
|
||||
assert.equal(panes.length, 2);
|
||||
assert.equal(panes[0].getItems()[0].getTitle(), 'Telemetry Consent');
|
||||
assert.equal(panes[0].getItems()[1].getTitle(), 'Welcome');
|
||||
assert.equal(panes[0].getItems()[0].getTitle(), 'Welcome');
|
||||
assert.equal(panes[1].getItems()[0].getTitle(), 'Welcome Guide');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when `core.telemetryConsent` is not `undecided`', () => {
|
||||
describe('when welcomePackage.activate is called. (previously variation of telemetryConsent change)', () => {
|
||||
beforeEach(async () => {
|
||||
atom.config.set('core.telemetryConsent', 'no');
|
||||
await welcomePackage.activate();
|
||||
});
|
||||
|
||||
|
@ -589,8 +589,8 @@ describe('Config', () => {
|
||||
atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] })
|
||||
).toBe(55);
|
||||
|
||||
//advanceClock(150);
|
||||
atom.config.save();
|
||||
advanceClock(150);
|
||||
|
||||
savedSettings.length = 0;
|
||||
|
||||
atom.config.unset('foo.bar.baz', { scopeSelector: '.source.coffee' });
|
||||
@ -601,8 +601,8 @@ describe('Config', () => {
|
||||
atom.config.get('foo.bar.ok', { scope: ['.source.coffee'] })
|
||||
).toBe(20);
|
||||
|
||||
//advanceClock(150);
|
||||
atom.config.save();
|
||||
advanceClock(150);
|
||||
|
||||
expect(savedSettings[0]['.coffee.source']).toEqual({
|
||||
foo: {
|
||||
bar: {
|
||||
@ -613,8 +613,8 @@ describe('Config', () => {
|
||||
|
||||
atom.config.unset('foo.bar.ok', { scopeSelector: '.source.coffee' });
|
||||
|
||||
//advanceClock(150);
|
||||
atom.config.save();
|
||||
advanceClock(150);
|
||||
|
||||
expect(savedSettings.length).toBe(2);
|
||||
expect(savedSettings[1]['.coffee.source']).toBeUndefined();
|
||||
});
|
||||
@ -1268,8 +1268,7 @@ describe('Config', () => {
|
||||
|
||||
atom.config.set('foo.int', 50, { scopeSelector: '*' });
|
||||
|
||||
//advanceClock(100);
|
||||
atom.config.save();
|
||||
advanceClock(100);
|
||||
|
||||
expect(savedSettings[0]['*'].foo).toEqual({
|
||||
bar: 'baz',
|
||||
|
@ -18,7 +18,6 @@ describe('Smoke Test', () => {
|
||||
'*': {
|
||||
welcome: { showOnStartup: false },
|
||||
core: {
|
||||
telemetryConsent: 'no',
|
||||
disabledPackages: ['github']
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,6 @@ describe('AtomWindow', function() {
|
||||
'*':
|
||||
core:
|
||||
automaticallyUpdate: false
|
||||
telemetryConsent: "no"
|
||||
welcome:
|
||||
showOnStartup: false
|
||||
`;
|
||||
|
69
spec/spec-helper-functions.js
Normal file
69
spec/spec-helper-functions.js
Normal file
@ -0,0 +1,69 @@
|
||||
function mockDebounce(func, wait, immediate) {
|
||||
// This is nearly a copy paste implementation of Underscore's Debounce Function
|
||||
// The only reason this is being mocked is because the older implementation being used within
|
||||
// underscore-plus has a debounce that checks Date().getTime(), whereas the more recent version
|
||||
// and whats expected of the other mock's is Date.now
|
||||
// Meaning debounce is able to rely on system time, while the tests manipulate
|
||||
// the `window` time to test features that need time to pass between them.
|
||||
|
||||
var timeout, previous, args, result, context;
|
||||
|
||||
// Declaring Rest Arguments here, since its included elsewhere in underscore
|
||||
var restArguments = function(func, startIndex) {
|
||||
startIndex = startIndex == null ? func.length - 1 : +startIndex;
|
||||
return function() {
|
||||
var length = Math.max(arguments.length = startIndex, 0),
|
||||
rest = Array(length),
|
||||
index = 0;
|
||||
for (; index < length; index++) {
|
||||
rest[index] = arguments[index + startIndex];
|
||||
}
|
||||
switch (startIndex) {
|
||||
case 0: return func.call(this, rest);
|
||||
case 1: return func.call(this, arguments[0], rest);
|
||||
case 2: return func.call(this, arguments[0], arguments[1], rest);
|
||||
}
|
||||
var args = Array(startIndex + 1);
|
||||
for (index = 0; index < startIndex; index++) {
|
||||
args[index] = arguments[index];
|
||||
}
|
||||
args[startIndex] = rest;
|
||||
return func.apply(this, args);
|
||||
};
|
||||
};
|
||||
|
||||
// now this is whats from the original debounce
|
||||
var later = function() {
|
||||
// The original Debounce uses its own now.js function here, whereas we can use Date.now()
|
||||
var passed = Date.now() - previous;
|
||||
if (wait > passed) {
|
||||
timeout = setTimeout(later, wait - passed);
|
||||
} else {
|
||||
timeout = null;
|
||||
if (!immediate) result = func.apply(context, args);
|
||||
if (!timeout) args = context = null;
|
||||
}
|
||||
};
|
||||
|
||||
var debounced = restArguments(function(_args) {
|
||||
context = this;
|
||||
args = _args;
|
||||
previous = Date.now();
|
||||
if (!timeout) {
|
||||
timeout = setTimeout(later, wait);
|
||||
if (immediate) result = func.apply(context, args);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
debounced.cancel = function() {
|
||||
clearTimeout(timeout);
|
||||
timeout = args = context = null;
|
||||
};
|
||||
|
||||
return debounced;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mockDebounce,
|
||||
};
|
@ -1,339 +0,0 @@
|
||||
require 'jasmine-json'
|
||||
require '../src/window'
|
||||
require '../vendor/jasmine-jquery'
|
||||
path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
Grim = require 'grim'
|
||||
pathwatcher = require 'pathwatcher'
|
||||
FindParentDir = require 'find-parent-dir'
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
|
||||
TextEditor = require '../src/text-editor'
|
||||
TextEditorElement = require '../src/text-editor-element'
|
||||
TextMateLanguageMode = require '../src/text-mate-language-mode'
|
||||
TreeSitterLanguageMode = require '../src/tree-sitter-language-mode'
|
||||
{clipboard} = require 'electron'
|
||||
|
||||
jasmineStyle = document.createElement('style')
|
||||
jasmineStyle.textContent = atom.themes.loadStylesheet(atom.themes.resolveStylesheet('../static/jasmine'))
|
||||
document.head.appendChild(jasmineStyle)
|
||||
|
||||
fixturePackagesPath = path.resolve(__dirname, './fixtures/packages')
|
||||
atom.packages.packageDirPaths.unshift(fixturePackagesPath)
|
||||
|
||||
document.querySelector('html').style.overflow = 'auto'
|
||||
document.body.style.overflow = 'auto'
|
||||
|
||||
Set.prototype.jasmineToString = ->
|
||||
result = "Set {"
|
||||
first = true
|
||||
@forEach (element) ->
|
||||
result += ", " unless first
|
||||
result += element.toString()
|
||||
first = false
|
||||
result + "}"
|
||||
|
||||
Set.prototype.isEqual = (other) ->
|
||||
if other instanceof Set
|
||||
return false if @size isnt other.size
|
||||
values = @values()
|
||||
until (next = values.next()).done
|
||||
return false unless other.has(next.value)
|
||||
true
|
||||
else
|
||||
false
|
||||
|
||||
jasmine.getEnv().addEqualityTester (a, b) ->
|
||||
# Match jasmine.any's equality matching logic
|
||||
return a.jasmineMatches(b) if a?.jasmineMatches?
|
||||
return b.jasmineMatches(a) if b?.jasmineMatches?
|
||||
|
||||
# Use underscore's definition of equality for toEqual assertions
|
||||
_.isEqual(a, b)
|
||||
|
||||
if process.env.CI
|
||||
jasmine.getEnv().defaultTimeoutInterval = 120000
|
||||
else
|
||||
jasmine.getEnv().defaultTimeoutInterval = 5000
|
||||
|
||||
{testPaths} = atom.getLoadSettings()
|
||||
|
||||
if specPackagePath = FindParentDir.sync(testPaths[0], 'package.json')
|
||||
packageMetadata = require(path.join(specPackagePath, 'package.json'))
|
||||
specPackageName = packageMetadata.name
|
||||
|
||||
if specDirectory = FindParentDir.sync(testPaths[0], 'fixtures')
|
||||
specProjectPath = path.join(specDirectory, 'fixtures')
|
||||
else
|
||||
specProjectPath = require('os').tmpdir()
|
||||
|
||||
beforeEach ->
|
||||
# Do not clobber recent project history
|
||||
spyOn(Object.getPrototypeOf(atom.history), 'saveState').andReturn(Promise.resolve())
|
||||
|
||||
atom.project.setPaths([specProjectPath])
|
||||
|
||||
window.resetTimeouts()
|
||||
spyOn(_._, "now").andCallFake -> window.now
|
||||
spyOn(Date, 'now').andCallFake(-> window.now)
|
||||
spyOn(window, "setTimeout").andCallFake window.fakeSetTimeout
|
||||
spyOn(window, "clearTimeout").andCallFake window.fakeClearTimeout
|
||||
|
||||
spy = spyOn(atom.packages, 'resolvePackagePath').andCallFake (packageName) ->
|
||||
if specPackageName and packageName is specPackageName
|
||||
resolvePackagePath(specPackagePath)
|
||||
else
|
||||
resolvePackagePath(packageName)
|
||||
resolvePackagePath = _.bind(spy.originalValue, atom.packages)
|
||||
|
||||
# prevent specs from modifying Atom's menus
|
||||
spyOn(atom.menu, 'sendToBrowserProcess')
|
||||
|
||||
# reset config before each spec
|
||||
atom.config.set "core.destroyEmptyPanes", false
|
||||
atom.config.set "editor.fontFamily", "Courier"
|
||||
atom.config.set "editor.fontSize", 16
|
||||
atom.config.set "editor.autoIndent", false
|
||||
atom.config.set "core.disabledPackages", ["package-that-throws-an-exception",
|
||||
"package-with-broken-package-json", "package-with-broken-keymap"]
|
||||
advanceClock(1000)
|
||||
window.setTimeout.reset()
|
||||
|
||||
# make editor display updates synchronous
|
||||
TextEditorElement::setUpdatedSynchronously(true)
|
||||
|
||||
spyOn(pathwatcher.File.prototype, "detectResurrectionAfterDelay").andCallFake -> @detectResurrection()
|
||||
spyOn(TextEditor.prototype, "shouldPromptToSave").andReturn false
|
||||
|
||||
# make tokenization synchronous
|
||||
TextMateLanguageMode.prototype.chunkSize = Infinity
|
||||
TreeSitterLanguageMode.prototype.syncTimeoutMicros = Infinity
|
||||
spyOn(TextMateLanguageMode.prototype, "tokenizeInBackground").andCallFake -> @tokenizeNextChunk()
|
||||
|
||||
# Without this spy, TextEditor.onDidTokenize callbacks would not be called
|
||||
# after the buffer's language mode changed, because by the time the editor
|
||||
# called its new language mode's onDidTokenize method, the language mode
|
||||
# would already be fully tokenized.
|
||||
spyOn(TextEditor.prototype, "onDidTokenize").andCallFake (callback) ->
|
||||
new CompositeDisposable(
|
||||
@emitter.on("did-tokenize", callback),
|
||||
@onDidChangeGrammar =>
|
||||
languageMode = @buffer.getLanguageMode()
|
||||
if languageMode.tokenizeInBackground?.originalValue
|
||||
callback()
|
||||
)
|
||||
|
||||
clipboardContent = 'initial clipboard content'
|
||||
spyOn(clipboard, 'writeText').andCallFake (text) -> clipboardContent = text
|
||||
spyOn(clipboard, 'readText').andCallFake -> clipboardContent
|
||||
|
||||
addCustomMatchers(this)
|
||||
|
||||
afterEach ->
|
||||
ensureNoDeprecatedFunctionCalls()
|
||||
ensureNoDeprecatedStylesheets()
|
||||
|
||||
waitsForPromise ->
|
||||
atom.reset()
|
||||
|
||||
runs ->
|
||||
document.getElementById('jasmine-content').innerHTML = '' unless window.debugContent
|
||||
warnIfLeakingPathSubscriptions()
|
||||
waits(0) # yield to ui thread to make screen update more frequently
|
||||
|
||||
warnIfLeakingPathSubscriptions = ->
|
||||
watchedPaths = pathwatcher.getWatchedPaths()
|
||||
if watchedPaths.length > 0
|
||||
console.error("WARNING: Leaking subscriptions for paths: " + watchedPaths.join(", "))
|
||||
pathwatcher.closeAllWatchers()
|
||||
|
||||
ensureNoDeprecatedFunctionCalls = ->
|
||||
deprecations = _.clone(Grim.getDeprecations())
|
||||
Grim.clearDeprecations()
|
||||
if deprecations.length > 0
|
||||
originalPrepareStackTrace = Error.prepareStackTrace
|
||||
Error.prepareStackTrace = (error, stack) ->
|
||||
output = []
|
||||
for deprecation in deprecations
|
||||
output.push "#{deprecation.originName} is deprecated. #{deprecation.message}"
|
||||
output.push _.multiplyString("-", output[output.length - 1].length)
|
||||
for stack in deprecation.getStacks()
|
||||
for {functionName, location} in stack
|
||||
output.push "#{functionName} -- #{location}"
|
||||
output.push ""
|
||||
output.join("\n")
|
||||
|
||||
error = new Error("Deprecated function(s) #{deprecations.map(({originName}) -> originName).join ', '}) were called.")
|
||||
error.stack
|
||||
Error.prepareStackTrace = originalPrepareStackTrace
|
||||
throw error
|
||||
|
||||
ensureNoDeprecatedStylesheets = ->
|
||||
deprecations = _.clone(atom.styles.getDeprecations())
|
||||
atom.styles.clearDeprecations()
|
||||
for sourcePath, deprecation of deprecations
|
||||
title =
|
||||
if sourcePath isnt 'undefined'
|
||||
"Deprecated stylesheet at '#{sourcePath}':"
|
||||
else
|
||||
"Deprecated stylesheet:"
|
||||
throw new Error("#{title}\n#{deprecation.message}")
|
||||
|
||||
emitObject = jasmine.StringPrettyPrinter.prototype.emitObject
|
||||
jasmine.StringPrettyPrinter.prototype.emitObject = (obj) ->
|
||||
if obj.inspect
|
||||
@append obj.inspect()
|
||||
else
|
||||
emitObject.call(this, obj)
|
||||
|
||||
jasmine.unspy = (object, methodName) ->
|
||||
throw new Error("Not a spy") unless object[methodName].hasOwnProperty('originalValue')
|
||||
object[methodName] = object[methodName].originalValue
|
||||
|
||||
jasmine.attachToDOM = (element) ->
|
||||
jasmineContent = document.querySelector('#jasmine-content')
|
||||
jasmineContent.appendChild(element) unless jasmineContent.contains(element)
|
||||
|
||||
grimDeprecationsSnapshot = null
|
||||
stylesDeprecationsSnapshot = null
|
||||
jasmine.snapshotDeprecations = ->
|
||||
grimDeprecationsSnapshot = _.clone(Grim.deprecations)
|
||||
stylesDeprecationsSnapshot = _.clone(atom.styles.deprecationsBySourcePath)
|
||||
|
||||
jasmine.restoreDeprecationsSnapshot = ->
|
||||
Grim.deprecations = grimDeprecationsSnapshot
|
||||
atom.styles.deprecationsBySourcePath = stylesDeprecationsSnapshot
|
||||
|
||||
jasmine.useRealClock = ->
|
||||
jasmine.unspy(window, 'setTimeout')
|
||||
jasmine.unspy(window, 'clearTimeout')
|
||||
jasmine.unspy(_._, 'now')
|
||||
jasmine.unspy(Date, 'now')
|
||||
|
||||
# The clock is halfway mocked now in a sad and terrible way... only setTimeout
|
||||
# and clearTimeout are included. This method will also include setInterval. We
|
||||
# would do this everywhere if didn't cause us to break a bunch of package tests.
|
||||
jasmine.useMockClock = ->
|
||||
spyOn(window, 'setInterval').andCallFake(fakeSetInterval)
|
||||
spyOn(window, 'clearInterval').andCallFake(fakeClearInterval)
|
||||
|
||||
addCustomMatchers = (spec) ->
|
||||
spec.addMatchers
|
||||
toBeInstanceOf: (expected) ->
|
||||
beOrNotBe = if @isNot then "not be" else "be"
|
||||
this.message = => "Expected #{jasmine.pp(@actual)} to #{beOrNotBe} instance of #{expected.name} class"
|
||||
@actual instanceof expected
|
||||
|
||||
toHaveLength: (expected) ->
|
||||
if not @actual?
|
||||
this.message = => "Expected object #{@actual} has no length method"
|
||||
false
|
||||
else
|
||||
haveOrNotHave = if @isNot then "not have" else "have"
|
||||
this.message = => "Expected object with length #{@actual.length} to #{haveOrNotHave} length #{expected}"
|
||||
@actual.length is expected
|
||||
|
||||
toExistOnDisk: (expected) ->
|
||||
toOrNotTo = this.isNot and "not to" or "to"
|
||||
@message = -> return "Expected path '#{@actual}' #{toOrNotTo} exist."
|
||||
fs.existsSync(@actual)
|
||||
|
||||
toHaveFocus: ->
|
||||
toOrNotTo = this.isNot and "not to" or "to"
|
||||
if not document.hasFocus()
|
||||
console.error "Specs will fail because the Dev Tools have focus. To fix this close the Dev Tools or click the spec runner."
|
||||
|
||||
@message = -> return "Expected element '#{@actual}' or its descendants #{toOrNotTo} have focus."
|
||||
element = @actual
|
||||
element = element.get(0) if element.jquery
|
||||
element is document.activeElement or element.contains(document.activeElement)
|
||||
|
||||
toShow: ->
|
||||
toOrNotTo = this.isNot and "not to" or "to"
|
||||
element = @actual
|
||||
element = element.get(0) if element.jquery
|
||||
@message = -> return "Expected element '#{element}' or its descendants #{toOrNotTo} show."
|
||||
computedStyle = getComputedStyle(element)
|
||||
computedStyle.display isnt 'none' and computedStyle.visibility is 'visible' and not element.hidden
|
||||
|
||||
toEqualPath: (expected) ->
|
||||
actualPath = path.normalize(@actual)
|
||||
expectedPath = path.normalize(expected)
|
||||
@message = -> return "Expected path '#{actualPath}' to be equal to '#{expectedPath}'."
|
||||
actualPath is expectedPath
|
||||
|
||||
toBeNear: (expected, acceptedError = 1, actual) ->
|
||||
return (typeof expected is 'number') and (typeof acceptedError is 'number') and (typeof @actual is 'number') and (expected - acceptedError <= @actual) and (@actual <= expected + acceptedError)
|
||||
|
||||
toHaveNearPixels: (expected, acceptedError = 1, actual) ->
|
||||
expectedNumber = parseFloat(expected)
|
||||
actualNumber = parseFloat(@actual)
|
||||
return (typeof expected is 'string') and (typeof acceptedError is 'number') and (typeof @actual is 'string') and (expected.indexOf('px') >= 1) and (@actual.indexOf('px') >= 1) and (expectedNumber - acceptedError <= actualNumber) and (actualNumber <= expectedNumber + acceptedError)
|
||||
|
||||
window.waitsForPromise = (args...) ->
|
||||
label = null
|
||||
if args.length > 1
|
||||
{shouldReject, timeout, label} = args[0]
|
||||
else
|
||||
shouldReject = false
|
||||
label ?= 'promise to be resolved or rejected'
|
||||
fn = _.last(args)
|
||||
|
||||
window.waitsFor label, timeout, (moveOn) ->
|
||||
promise = fn()
|
||||
if shouldReject
|
||||
promise.catch.call(promise, moveOn)
|
||||
promise.then ->
|
||||
jasmine.getEnv().currentSpec.fail("Expected promise to be rejected, but it was resolved")
|
||||
moveOn()
|
||||
else
|
||||
promise.then(moveOn)
|
||||
promise.catch.call promise, (error) ->
|
||||
jasmine.getEnv().currentSpec.fail("Expected promise to be resolved, but it was rejected with: #{error?.message} #{jasmine.pp(error)}")
|
||||
moveOn()
|
||||
|
||||
window.resetTimeouts = ->
|
||||
window.now = 0
|
||||
window.timeoutCount = 0
|
||||
window.intervalCount = 0
|
||||
window.timeouts = []
|
||||
window.intervalTimeouts = {}
|
||||
|
||||
window.fakeSetTimeout = (callback, ms=0) ->
|
||||
id = ++window.timeoutCount
|
||||
window.timeouts.push([id, window.now + ms, callback])
|
||||
id
|
||||
|
||||
window.fakeClearTimeout = (idToClear) ->
|
||||
window.timeouts = window.timeouts.filter ([id]) -> id isnt idToClear
|
||||
|
||||
window.fakeSetInterval = (callback, ms) ->
|
||||
id = ++window.intervalCount
|
||||
action = ->
|
||||
callback()
|
||||
window.intervalTimeouts[id] = window.fakeSetTimeout(action, ms)
|
||||
window.intervalTimeouts[id] = window.fakeSetTimeout(action, ms)
|
||||
id
|
||||
|
||||
window.fakeClearInterval = (idToClear) ->
|
||||
window.fakeClearTimeout(@intervalTimeouts[idToClear])
|
||||
|
||||
window.advanceClock = (delta=1) ->
|
||||
window.now += delta
|
||||
callbacks = []
|
||||
|
||||
window.timeouts = window.timeouts.filter ([id, strikeTime, callback]) ->
|
||||
if strikeTime <= window.now
|
||||
callbacks.push(callback)
|
||||
false
|
||||
else
|
||||
true
|
||||
|
||||
callback() for callback in callbacks
|
||||
|
||||
exports.mockLocalStorage = ->
|
||||
items = {}
|
||||
spyOn(global.localStorage, 'setItem').andCallFake (key, item) -> items[key] = item.toString(); undefined
|
||||
spyOn(global.localStorage, 'getItem').andCallFake (key) -> items[key] ? null
|
||||
spyOn(global.localStorage, 'removeItem').andCallFake (key) -> delete items[key]; undefined
|
432
spec/spec-helper.js
Normal file
432
spec/spec-helper.js
Normal file
@ -0,0 +1,432 @@
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS101: Remove unnecessary use of Array.from
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS201: Simplify complex destructure assignments
|
||||
* DS205: Consider reworking code to avoid use of IIFEs
|
||||
* DS207: Consider shorter variations of null checks
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
|
||||
*/
|
||||
let specDirectory, specPackageName, specPackagePath, specProjectPath;
|
||||
require('jasmine-json');
|
||||
require('../src/window');
|
||||
require('../vendor/jasmine-jquery');
|
||||
const path = require('path');
|
||||
const _ = require('underscore-plus');
|
||||
const fs = require('fs-plus');
|
||||
const Grim = require('grim');
|
||||
const pathwatcher = require('pathwatcher');
|
||||
const FindParentDir = require('find-parent-dir');
|
||||
const {CompositeDisposable} = require('event-kit');
|
||||
|
||||
const TextEditor = require('../src/text-editor');
|
||||
const TextEditorElement = require('../src/text-editor-element');
|
||||
const TextMateLanguageMode = require('../src/text-mate-language-mode');
|
||||
const TreeSitterLanguageMode = require('../src/tree-sitter-language-mode');
|
||||
const {clipboard} = require('electron');
|
||||
const {mockDebounce} = require("./spec-helper-functions.js");
|
||||
|
||||
const jasmineStyle = document.createElement('style');
|
||||
jasmineStyle.textContent = atom.themes.loadStylesheet(atom.themes.resolveStylesheet('../static/jasmine'));
|
||||
document.head.appendChild(jasmineStyle);
|
||||
|
||||
const fixturePackagesPath = path.resolve(__dirname, './fixtures/packages');
|
||||
atom.packages.packageDirPaths.unshift(fixturePackagesPath);
|
||||
|
||||
document.querySelector('html').style.overflow = 'auto';
|
||||
document.body.style.overflow = 'auto';
|
||||
|
||||
Set.prototype.jasmineToString = function() {
|
||||
let result = "Set {";
|
||||
let first = true;
|
||||
this.forEach(function(element) {
|
||||
if (!first) { result += ", "; }
|
||||
return result += element.toString();
|
||||
});
|
||||
first = false;
|
||||
return result + "}";
|
||||
};
|
||||
|
||||
Set.prototype.isEqual = function(other) {
|
||||
if (other instanceof Set) {
|
||||
let next;
|
||||
if (this.size !== other.size) { return false; }
|
||||
const values = this.values();
|
||||
while (!(next = values.next()).done) {
|
||||
if (!other.has(next.value)) { return false; }
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
jasmine.getEnv().addEqualityTester(function(a, b) {
|
||||
// Match jasmine.any's equality matching logic
|
||||
if ((a != null ? a.jasmineMatches : undefined) != null) { return a.jasmineMatches(b); }
|
||||
if ((b != null ? b.jasmineMatches : undefined) != null) { return b.jasmineMatches(a); }
|
||||
|
||||
// Use underscore's definition of equality for toEqual assertions
|
||||
return _.isEqual(a, b);
|
||||
});
|
||||
|
||||
if (process.env.CI) {
|
||||
jasmine.getEnv().defaultTimeoutInterval = 120000;
|
||||
} else {
|
||||
jasmine.getEnv().defaultTimeoutInterval = 5000;
|
||||
}
|
||||
|
||||
const {testPaths} = atom.getLoadSettings();
|
||||
|
||||
if (specPackagePath = FindParentDir.sync(testPaths[0], 'package.json')) {
|
||||
const packageMetadata = require(path.join(specPackagePath, 'package.json'));
|
||||
specPackageName = packageMetadata.name;
|
||||
}
|
||||
|
||||
if ((specDirectory = FindParentDir.sync(testPaths[0], 'fixtures'))) {
|
||||
specProjectPath = path.join(specDirectory, 'fixtures');
|
||||
} else {
|
||||
specProjectPath = require('os').tmpdir();
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
// Do not clobber recent project history
|
||||
spyOn(Object.getPrototypeOf(atom.history), 'saveState').andReturn(Promise.resolve());
|
||||
|
||||
atom.project.setPaths([specProjectPath]);
|
||||
|
||||
window.resetTimeouts();
|
||||
spyOn(_._, "now").andCallFake(() => window.now);
|
||||
spyOn(Date, 'now').andCallFake(() => window.now);
|
||||
spyOn(window, "setTimeout").andCallFake(window.fakeSetTimeout);
|
||||
spyOn(window, "clearTimeout").andCallFake(window.fakeClearTimeout);
|
||||
spyOn(_, "debounce").andCallFake(mockDebounce);
|
||||
|
||||
const spy = spyOn(atom.packages, 'resolvePackagePath').andCallFake(function(packageName) {
|
||||
if (specPackageName && (packageName === specPackageName)) {
|
||||
return resolvePackagePath(specPackagePath);
|
||||
} else {
|
||||
return resolvePackagePath(packageName);
|
||||
}
|
||||
});
|
||||
var resolvePackagePath = _.bind(spy.originalValue, atom.packages);
|
||||
|
||||
// prevent specs from modifying Atom's menus
|
||||
spyOn(atom.menu, 'sendToBrowserProcess');
|
||||
|
||||
// reset config before each spec
|
||||
atom.config.set("core.destroyEmptyPanes", false);
|
||||
atom.config.set("editor.fontFamily", "Courier");
|
||||
atom.config.set("editor.fontSize", 16);
|
||||
atom.config.set("editor.autoIndent", false);
|
||||
atom.config.set("core.disabledPackages", ["package-that-throws-an-exception",
|
||||
"package-with-broken-package-json", "package-with-broken-keymap"]);
|
||||
advanceClock(1000);
|
||||
window.setTimeout.reset();
|
||||
|
||||
// make editor display updates synchronous
|
||||
TextEditorElement.prototype.setUpdatedSynchronously(true);
|
||||
|
||||
spyOn(pathwatcher.File.prototype, "detectResurrectionAfterDelay").andCallFake(function() { return this.detectResurrection(); });
|
||||
spyOn(TextEditor.prototype, "shouldPromptToSave").andReturn(false);
|
||||
|
||||
// make tokenization synchronous
|
||||
TextMateLanguageMode.prototype.chunkSize = Infinity;
|
||||
TreeSitterLanguageMode.prototype.syncTimeoutMicros = Infinity;
|
||||
spyOn(TextMateLanguageMode.prototype, "tokenizeInBackground").andCallFake(function() { return this.tokenizeNextChunk(); });
|
||||
|
||||
// Without this spy, TextEditor.onDidTokenize callbacks would not be called
|
||||
// after the buffer's language mode changed, because by the time the editor
|
||||
// called its new language mode's onDidTokenize method, the language mode
|
||||
// would already be fully tokenized.
|
||||
spyOn(TextEditor.prototype, "onDidTokenize").andCallFake(function(callback) {
|
||||
return new CompositeDisposable(
|
||||
this.emitter.on("did-tokenize", callback),
|
||||
this.onDidChangeGrammar(() => {
|
||||
const languageMode = this.buffer.getLanguageMode();
|
||||
if (languageMode.tokenizeInBackground != null ? languageMode.tokenizeInBackground.originalValue : undefined) {
|
||||
return callback();
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
let clipboardContent = 'initial clipboard content';
|
||||
spyOn(clipboard, 'writeText').andCallFake(text => clipboardContent = text);
|
||||
spyOn(clipboard, 'readText').andCallFake(() => clipboardContent);
|
||||
|
||||
return addCustomMatchers(this);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
ensureNoDeprecatedFunctionCalls();
|
||||
ensureNoDeprecatedStylesheets();
|
||||
|
||||
waitsForPromise(() => atom.reset());
|
||||
|
||||
return runs(function() {
|
||||
if (!window.debugContent) { document.getElementById('jasmine-content').innerHTML = ''; }
|
||||
warnIfLeakingPathSubscriptions();
|
||||
return waits(0);
|
||||
});
|
||||
}); // yield to ui thread to make screen update more frequently
|
||||
|
||||
var warnIfLeakingPathSubscriptions = function() {
|
||||
const watchedPaths = pathwatcher.getWatchedPaths();
|
||||
if (watchedPaths.length > 0) {
|
||||
console.error("WARNING: Leaking subscriptions for paths: " + watchedPaths.join(", "));
|
||||
}
|
||||
return pathwatcher.closeAllWatchers();
|
||||
};
|
||||
|
||||
var ensureNoDeprecatedFunctionCalls = function() {
|
||||
const deprecations = _.clone(Grim.getDeprecations());
|
||||
Grim.clearDeprecations();
|
||||
if (deprecations.length > 0) {
|
||||
const originalPrepareStackTrace = Error.prepareStackTrace;
|
||||
Error.prepareStackTrace = function(error, stack) {
|
||||
const output = [];
|
||||
for (let deprecation of Array.from(deprecations)) {
|
||||
output.push(`${deprecation.originName} is deprecated. ${deprecation.message}`);
|
||||
output.push(_.multiplyString("-", output[output.length - 1].length));
|
||||
for (stack of Array.from(deprecation.getStacks())) {
|
||||
for (let {functionName, location} of Array.from(stack)) {
|
||||
output.push(`${functionName} -- ${location}`);
|
||||
}
|
||||
}
|
||||
output.push("");
|
||||
}
|
||||
return output.join("\n");
|
||||
};
|
||||
|
||||
const error = new Error(`Deprecated function(s) ${deprecations.map(({originName}) => originName).join(', ')}) were called.`);
|
||||
error.stack;
|
||||
Error.prepareStackTrace = originalPrepareStackTrace;
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
var ensureNoDeprecatedStylesheets = function() {
|
||||
const deprecations = _.clone(atom.styles.getDeprecations());
|
||||
atom.styles.clearDeprecations();
|
||||
return (() => {
|
||||
const result = [];
|
||||
for (let sourcePath in deprecations) {
|
||||
const deprecation = deprecations[sourcePath];
|
||||
const title =
|
||||
sourcePath !== 'undefined' ?
|
||||
`Deprecated stylesheet at '${sourcePath}':`
|
||||
:
|
||||
"Deprecated stylesheet:";
|
||||
throw new Error(`${title}\n${deprecation.message}`);
|
||||
}
|
||||
return result;
|
||||
})();
|
||||
};
|
||||
|
||||
const {
|
||||
emitObject
|
||||
} = jasmine.StringPrettyPrinter.prototype;
|
||||
jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
|
||||
if (obj.inspect) {
|
||||
return this.append(obj.inspect());
|
||||
} else {
|
||||
return emitObject.call(this, obj);
|
||||
}
|
||||
};
|
||||
|
||||
jasmine.unspy = function(object, methodName) {
|
||||
if (!object[methodName].hasOwnProperty('originalValue')) { throw new Error("Not a spy"); }
|
||||
return object[methodName] = object[methodName].originalValue;
|
||||
};
|
||||
|
||||
jasmine.attachToDOM = function(element) {
|
||||
const jasmineContent = document.querySelector('#jasmine-content');
|
||||
if (!jasmineContent.contains(element)) { return jasmineContent.appendChild(element); }
|
||||
};
|
||||
|
||||
let grimDeprecationsSnapshot = null;
|
||||
let stylesDeprecationsSnapshot = null;
|
||||
jasmine.snapshotDeprecations = function() {
|
||||
grimDeprecationsSnapshot = _.clone(Grim.deprecations);
|
||||
return stylesDeprecationsSnapshot = _.clone(atom.styles.deprecationsBySourcePath);
|
||||
};
|
||||
|
||||
jasmine.restoreDeprecationsSnapshot = function() {
|
||||
Grim.deprecations = grimDeprecationsSnapshot;
|
||||
return atom.styles.deprecationsBySourcePath = stylesDeprecationsSnapshot;
|
||||
};
|
||||
|
||||
jasmine.useRealClock = function() {
|
||||
jasmine.unspy(window, 'setTimeout');
|
||||
jasmine.unspy(window, 'clearTimeout');
|
||||
jasmine.unspy(_._, 'now');
|
||||
return jasmine.unspy(Date, 'now');
|
||||
};
|
||||
|
||||
// The clock is halfway mocked now in a sad and terrible way... only setTimeout
|
||||
// and clearTimeout are included. This method will also include setInterval. We
|
||||
// would do this everywhere if didn't cause us to break a bunch of package tests.
|
||||
jasmine.useMockClock = function() {
|
||||
spyOn(window, 'setInterval').andCallFake(fakeSetInterval);
|
||||
return spyOn(window, 'clearInterval').andCallFake(fakeClearInterval);
|
||||
};
|
||||
|
||||
var addCustomMatchers = function(spec) {
|
||||
return spec.addMatchers({
|
||||
toBeInstanceOf(expected) {
|
||||
const beOrNotBe = this.isNot ? "not be" : "be";
|
||||
this.message = () => `Expected ${jasmine.pp(this.actual)} to ${beOrNotBe} instance of ${expected.name} class`;
|
||||
return this.actual instanceof expected;
|
||||
},
|
||||
|
||||
toHaveLength(expected) {
|
||||
if ((this.actual == null)) {
|
||||
this.message = () => `Expected object ${this.actual} has no length method`;
|
||||
return false;
|
||||
} else {
|
||||
const haveOrNotHave = this.isNot ? "not have" : "have";
|
||||
this.message = () => `Expected object with length ${this.actual.length} to ${haveOrNotHave} length ${expected}`;
|
||||
return this.actual.length === expected;
|
||||
}
|
||||
},
|
||||
|
||||
toExistOnDisk(expected) {
|
||||
const toOrNotTo = (this.isNot && "not to") || "to";
|
||||
this.message = function() { return `Expected path '${this.actual}' ${toOrNotTo} exist.`; };
|
||||
return fs.existsSync(this.actual);
|
||||
},
|
||||
|
||||
toHaveFocus() {
|
||||
const toOrNotTo = (this.isNot && "not to") || "to";
|
||||
if (!document.hasFocus()) {
|
||||
console.error("Specs will fail because the Dev Tools have focus. To fix this close the Dev Tools or click the spec runner.");
|
||||
}
|
||||
|
||||
this.message = function() { return `Expected element '${this.actual}' or its descendants ${toOrNotTo} have focus.`; };
|
||||
let element = this.actual;
|
||||
if (element.jquery) { element = element.get(0); }
|
||||
return (element === document.activeElement) || element.contains(document.activeElement);
|
||||
},
|
||||
|
||||
toShow() {
|
||||
const toOrNotTo = (this.isNot && "not to") || "to";
|
||||
let element = this.actual;
|
||||
if (element.jquery) { element = element.get(0); }
|
||||
this.message = () => `Expected element '${element}' or its descendants ${toOrNotTo} show.`;
|
||||
const computedStyle = getComputedStyle(element);
|
||||
return (computedStyle.display !== 'none') && (computedStyle.visibility === 'visible') && !element.hidden;
|
||||
},
|
||||
|
||||
toEqualPath(expected) {
|
||||
const actualPath = path.normalize(this.actual);
|
||||
const expectedPath = path.normalize(expected);
|
||||
this.message = () => `Expected path '${actualPath}' to be equal to '${expectedPath}'.`;
|
||||
return actualPath === expectedPath;
|
||||
},
|
||||
|
||||
toBeNear(expected, acceptedError, actual) {
|
||||
if (acceptedError == null) { acceptedError = 1; }
|
||||
return (typeof expected === 'number') && (typeof acceptedError === 'number') && (typeof this.actual === 'number') && ((expected - acceptedError) <= this.actual) && (this.actual <= (expected + acceptedError));
|
||||
},
|
||||
|
||||
toHaveNearPixels(expected, acceptedError, actual) {
|
||||
if (acceptedError == null) { acceptedError = 1; }
|
||||
const expectedNumber = parseFloat(expected);
|
||||
const actualNumber = parseFloat(this.actual);
|
||||
return (typeof expected === 'string') && (typeof acceptedError === 'number') && (typeof this.actual === 'string') && (expected.indexOf('px') >= 1) && (this.actual.indexOf('px') >= 1) && ((expectedNumber - acceptedError) <= actualNumber) && (actualNumber <= (expectedNumber + acceptedError));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
window.waitsForPromise = function(...args) {
|
||||
let shouldReject, timeout;
|
||||
let label = null;
|
||||
if (args.length > 1) {
|
||||
({shouldReject, timeout, label} = args[0]);
|
||||
} else {
|
||||
shouldReject = false;
|
||||
}
|
||||
if (label == null) { label = 'promise to be resolved or rejected'; }
|
||||
const fn = _.last(args);
|
||||
|
||||
return window.waitsFor(label, timeout, function(moveOn) {
|
||||
const promise = fn();
|
||||
if (shouldReject) {
|
||||
promise.catch.call(promise, moveOn);
|
||||
return promise.then(function() {
|
||||
jasmine.getEnv().currentSpec.fail("Expected promise to be rejected, but it was resolved");
|
||||
return moveOn();
|
||||
});
|
||||
} else {
|
||||
promise.then(moveOn);
|
||||
return promise.catch.call(promise, function(error) {
|
||||
jasmine.getEnv().currentSpec.fail(`Expected promise to be resolved, but it was rejected with: ${(error != null ? error.message : undefined)} ${jasmine.pp(error)}`);
|
||||
return moveOn();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
window.resetTimeouts = function() {
|
||||
window.now = 0;
|
||||
window.timeoutCount = 0;
|
||||
window.intervalCount = 0;
|
||||
window.timeouts = [];
|
||||
return window.intervalTimeouts = {};
|
||||
};
|
||||
|
||||
window.fakeSetTimeout = function(callback, ms) {
|
||||
if (ms == null) { ms = 0; }
|
||||
const id = ++window.timeoutCount;
|
||||
window.timeouts.push([id, window.now + ms, callback]);
|
||||
return id;
|
||||
};
|
||||
|
||||
window.fakeClearTimeout = idToClear => window.timeouts = window.timeouts.filter(function(...args) { const [id] = Array.from(args[0]); return id !== idToClear; });
|
||||
|
||||
window.fakeSetInterval = function(callback, ms) {
|
||||
const id = ++window.intervalCount;
|
||||
var action = function() {
|
||||
callback();
|
||||
return window.intervalTimeouts[id] = window.fakeSetTimeout(action, ms);
|
||||
};
|
||||
window.intervalTimeouts[id] = window.fakeSetTimeout(action, ms);
|
||||
return id;
|
||||
};
|
||||
|
||||
window.fakeClearInterval = function(idToClear) {
|
||||
return window.fakeClearTimeout(this.intervalTimeouts[idToClear]);
|
||||
};
|
||||
|
||||
window.advanceClock = function(delta) {
|
||||
if (delta == null) { delta = 1; }
|
||||
window.now += delta;
|
||||
const callbacks = [];
|
||||
|
||||
window.timeouts = window.timeouts.filter(function(...args) {
|
||||
let id, strikeTime;
|
||||
let callback;
|
||||
[id, strikeTime, callback] = Array.from(args[0]);
|
||||
if (strikeTime <= window.now) {
|
||||
callbacks.push(callback);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
return (() => {
|
||||
const result = [];
|
||||
for (let callback of Array.from(callbacks)) { result.push(callback());
|
||||
}
|
||||
return result;
|
||||
})();
|
||||
};
|
||||
|
||||
exports.mockLocalStorage = function() {
|
||||
const items = {};
|
||||
spyOn(global.localStorage, 'setItem').andCallFake(function(key, item) { items[key] = item.toString(); return undefined; });
|
||||
spyOn(global.localStorage, 'getItem').andCallFake(key => items[key] != null ? items[key] : null);
|
||||
return spyOn(global.localStorage, 'removeItem').andCallFake(function(key) { delete items[key]; return undefined; });
|
||||
};
|
@ -339,29 +339,6 @@ const configSchema = {
|
||||
type: 'boolean',
|
||||
default: true
|
||||
},
|
||||
telemetryConsent: {
|
||||
description:
|
||||
'Allow usage statistics and exception reports to be sent to the Pulsar team to help improve the product.',
|
||||
title: 'Send Telemetry to the Pulsar Team',
|
||||
type: 'string',
|
||||
default: 'undecided',
|
||||
enum: [
|
||||
{
|
||||
value: 'limited',
|
||||
description:
|
||||
'Allow limited anonymous usage stats, exception and crash reporting'
|
||||
},
|
||||
{
|
||||
value: 'no',
|
||||
description: 'Do not send any telemetry data'
|
||||
},
|
||||
{
|
||||
value: 'undecided',
|
||||
description:
|
||||
'Undecided (Pulsar will ask again next time it is launched)'
|
||||
}
|
||||
]
|
||||
},
|
||||
warnOnLargeFileLimit: {
|
||||
description:
|
||||
'Warn before opening files larger than this number of megabytes.',
|
||||
|
@ -46,7 +46,6 @@ if (global.isGeneratingSnapshot) {
|
||||
require('line-ending-selector');
|
||||
require('link');
|
||||
require('markdown-preview');
|
||||
require('metrics');
|
||||
require('notifications');
|
||||
require('open-on-github');
|
||||
require('package-generator');
|
||||
|
@ -161,11 +161,6 @@
|
||||
};
|
||||
|
||||
const { userSettings, appVersion } = getWindowLoadSettings();
|
||||
const uploadToServer =
|
||||
userSettings &&
|
||||
userSettings.core &&
|
||||
userSettings.core.telemetryConsent === 'limited';
|
||||
const releaseChannel = getReleaseChannel(appVersion);
|
||||
|
||||
const CSON = useSnapshot
|
||||
? snapshotResult.customRequire('../node_modules/season/lib/cson.js')
|
||||
|
37
yarn.lock
37
yarn.lock
@ -5014,11 +5014,6 @@ iconv-lite@^0.6.2:
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3.0.0"
|
||||
|
||||
idb@^4.0.3:
|
||||
version "4.0.5"
|
||||
resolved "https://registry.yarnpkg.com/idb/-/idb-4.0.5.tgz#23b930fbb0abce391e939c35b7b31a669e74041f"
|
||||
integrity sha512-P+Fk9HT2h1DhXoE1YNK183SY+CRh2GHNh28de94sGwhe0bUA75JJeVJWt3SenE5p0BXK7maflIq29dl6UZHrFw==
|
||||
|
||||
ieee754@^1.1.13:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
|
||||
@ -5962,11 +5957,6 @@ loglevel@^1.6.0:
|
||||
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.0.tgz#e7ec73a57e1e7b419cb6c6ac06bf050b67356114"
|
||||
integrity sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA==
|
||||
|
||||
lokijs@^1.5.4:
|
||||
version "1.5.12"
|
||||
resolved "https://registry.yarnpkg.com/lokijs/-/lokijs-1.5.12.tgz#cb55b37009bdf09ee7952a6adddd555b893653a0"
|
||||
integrity sha512-Q5ALD6JiS6xAUWCwX3taQmgwxyveCtIIuL08+ml0nHwT3k0S/GIFJN+Hd38b1qYIMaE5X++iqsqWVksz7SYW+Q==
|
||||
|
||||
loophole@^1:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/loophole/-/loophole-1.1.0.tgz#37949fea453b6256acc725c320ce0c5a7f70a2bd"
|
||||
@ -6127,14 +6117,6 @@ md5@^2.1.0:
|
||||
crypt "0.0.2"
|
||||
is-buffer "~1.1.6"
|
||||
|
||||
"metrics@https://codeload.github.com/atom/metrics/legacy.tar.gz/refs/tags/v1.8.1":
|
||||
version "1.8.1"
|
||||
resolved "https://codeload.github.com/atom/metrics/legacy.tar.gz/refs/tags/v1.8.1#fbf921b4c9212a11f83d1f580620c3d6b1fff974"
|
||||
dependencies:
|
||||
fs-plus "^3.0.0"
|
||||
grim "^2.0.1"
|
||||
telemetry-github "0.1.1"
|
||||
|
||||
mime-db@1.52.0:
|
||||
version "1.52.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
|
||||
@ -8506,23 +8488,6 @@ tar@^6.0.2, tar@^6.0.5, tar@^6.1.11, tar@^6.1.2:
|
||||
mkdirp "^1.0.3"
|
||||
yallist "^4.0.0"
|
||||
|
||||
telemetry-github@0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/telemetry-github/-/telemetry-github-0.1.1.tgz#ae3d159e914d124dc1debd042fc2e276ce847df4"
|
||||
integrity sha512-UUtkNKKHpUthL4FsAJDqKg+TiW0DBI636XAOAA3qcu86m20DhLhn3qhxl12joGdPBtk0tbv/Dx47pj28ZhuF+g==
|
||||
dependencies:
|
||||
idb "^4.0.3"
|
||||
lokijs "^1.5.4"
|
||||
uuid "^3.2.1"
|
||||
|
||||
temp-file@^3.4.0:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/temp-file/-/temp-file-3.4.0.tgz#766ea28911c683996c248ef1a20eea04d51652c7"
|
||||
integrity sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==
|
||||
dependencies:
|
||||
async-exit-hook "^2.0.1"
|
||||
fs-extra "^10.0.0"
|
||||
|
||||
temp@0.9.1:
|
||||
version "0.9.1"
|
||||
resolved "https://registry.yarnpkg.com/temp/-/temp-0.9.1.tgz#2d666114fafa26966cd4065996d7ceedd4dd4697"
|
||||
@ -9015,7 +8980,7 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
|
||||
|
||||
uuid@^3.0.0, uuid@^3.2.1, uuid@^3.3.2:
|
||||
uuid@^3.0.0, uuid@^3.3.2:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||
|
Loading…
Reference in New Issue
Block a user