UNPKG

@shopify/theme-language-server-common

Version:

<h1 align="center" style="position: relative;" > <br> <img src="https://github.com/Shopify/theme-check-vscode/blob/main/images/shopify_glyph.png?raw=true" alt="logo" width="141" height="160"> <br> Theme Language Server </h1>

136 lines (121 loc) 4.6 kB
import { describe, it, expect, vi, beforeEach, Mock } from 'vitest'; import { URI } from 'vscode-uri'; import { Offense, SourceCodeType, Severity, Position, Suggestion, path, } from '@shopify/theme-check-common'; import { DiagnosticsManager } from '../../diagnostics'; import { DocumentManager } from '../../documents'; import { ApplySuggestionProvider } from './ApplySuggestionProvider'; import { TextDocument } from 'vscode-languageserver-textdocument'; import { offenseToDiagnostic } from '../../diagnostics/offenseToDiagnostic'; describe('Unit: ApplySuggestionProvider', () => { const uri = path.normalize(URI.file('/path/to/file.liquid')); const contents = ` {% assign x = 1 %} <script src="2.js"></script> <script src="3.js"></script> `; const version = 0; const document = TextDocument.create(uri, 'liquid', version, contents); let connection: { sendDiagnostics: Mock; sendRequest: Mock }; let documentManager: DocumentManager; let diagnosticsManager: DiagnosticsManager; let applySuggestionProvider: ApplySuggestionProvider; function makeOffense( checkName: string, needle: string, unfixable?: boolean, ): Offense<SourceCodeType.LiquidHtml> { const start = contents.indexOf(needle); const end = start + needle.length; const suggestion = (replaceWith: string): Suggestion<SourceCodeType.LiquidHtml> => ({ message: `Replace with ${replaceWith}`, fix: (corrector) => corrector.replace(start, end, replaceWith), }); return { type: SourceCodeType.LiquidHtml, check: checkName, message: 'Parser blocking script detected', uri: 'file:///path/to/file.liquid', severity: Severity.ERROR, start: { ...document.positionAt(start), index: start }, end: { ...document.positionAt(end), index: end }, suggest: unfixable ? undefined : [suggestion('defer'), suggestion('async')], }; } beforeEach(() => { connection = { sendRequest: vi.fn(), sendDiagnostics: vi.fn() }; documentManager = new DocumentManager(); diagnosticsManager = new DiagnosticsManager(connection as any); documentManager.open(uri, contents, version); const capabilities = { hasApplyEditSupport: vi.fn().mockReturnValue(true) }; applySuggestionProvider = new ApplySuggestionProvider( documentManager, diagnosticsManager, capabilities as any, connection as any, ); }); describe('execute', () => { it('applies the suggestion for the given offense id and suggestion index', async () => { const offenses = [ makeOffense('Offense1', '{% assign x = 1 %}'), makeOffense('Offense2', '<script src="2.js"></script>'), makeOffense('Offense3', '<script src="3.js"></script>'), ]; diagnosticsManager.set(uri, version, offenses); const offenseId = 1; // 2.js const suggestionIndex = 1; // async await applySuggestionProvider.execute(uri, version, offenseId, suggestionIndex); expect(connection.sendRequest).toHaveBeenCalledWith(expect.anything(), { label: 'Apply suggestion: Replace with async', edit: { documentChanges: [ { textDocument: expect.anything(), edits: [ { newText: 'async', range: { start: asLspPosition(offenses[1].start), end: asLspPosition(offenses[1].end), }, }, ], }, ], }, }); // We clean up stale diagnostics when we're done expect(connection.sendDiagnostics).toHaveBeenCalledWith({ uri: expect.anything(), version: expect.any(Number), diagnostics: offenses.filter((_, index) => index !== offenseId).map(offenseToDiagnostic), }); }); it('does not apply fixes if the document or diagnostics are not available', async () => { const offenses = [ makeOffense('Offense1', '{% assign x = 1 %}'), makeOffense('Offense2', '<script src="2.js"></script>'), makeOffense('Offense3', '<script src="3.js"></script>'), ]; diagnosticsManager.set(uri, 0, offenses); documentManager.close(uri); await applySuggestionProvider.execute(uri, 1, 0, 0); expect(connection.sendRequest).not.toHaveBeenCalled(); }); }); }); function omit(obj: any, key: string) { const clone = { ...obj }; delete clone[key]; return clone; } function asLspPosition(position: Position): any { return omit(position, 'index'); }