VerifyCodeFixAll verifies that applying all code fixes with the given fixId produces the expected file content. It gets all quickfix code actions for the file (which includes per-fixId "Fix all" entries when multiple diagnostics match the same provider), finds the fix-all entry, and applies its edit
(t *testing.T, options VerifyCodeFixAllOptions)
| 1812 | // It gets all quickfix code actions for the file (which includes per-fixId "Fix all" entries when |
| 1813 | // multiple diagnostics match the same provider), finds the fix-all entry, and applies its edits. |
| 1814 | func (f *FourslashTest) VerifyCodeFixAll(t *testing.T, options VerifyCodeFixAllOptions) { |
| 1815 | t.Helper() |
| 1816 | |
| 1817 | actions := f.getAllQuickFixActions(t) |
| 1818 | if len(actions) == 0 { |
| 1819 | t.Fatalf("No code fixes available for fixId %q", options.FixID) |
| 1820 | } |
| 1821 | |
| 1822 | // Find fix-all actions. The server returns these as quickfix entries with titles like |
| 1823 | // "Add all missing imports" when multiple diagnostics match the same provider. |
| 1824 | // We look for actions that are NOT single-diagnostic fixes (i.e., have no Diagnostics attached). |
| 1825 | var fixAllCandidates []*lsproto.CodeAction |
| 1826 | for _, action := range actions { |
| 1827 | if action.Diagnostics == nil || len(*action.Diagnostics) == 0 { |
| 1828 | fixAllCandidates = append(fixAllCandidates, action) |
| 1829 | } |
| 1830 | } |
| 1831 | |
| 1832 | var fixAllAction *lsproto.CodeAction |
| 1833 | if len(fixAllCandidates) == 1 { |
| 1834 | fixAllAction = fixAllCandidates[0] |
| 1835 | } else { |
| 1836 | // If there are multiple fix-all candidates, match by FixID in the title. |
| 1837 | for _, action := range fixAllCandidates { |
| 1838 | if strings.Contains(strings.ToLower(action.Title), strings.ToLower(options.FixID)) { |
| 1839 | fixAllAction = action |
| 1840 | break |
| 1841 | } |
| 1842 | } |
| 1843 | } |
| 1844 | |
| 1845 | if fixAllAction == nil { |
| 1846 | var titles []string |
| 1847 | for _, a := range actions { |
| 1848 | titles = append(titles, a.Title) |
| 1849 | } |
| 1850 | t.Fatalf("No fix-all code action found for fixId %q. Available fixes: %v", options.FixID, titles) |
| 1851 | } |
| 1852 | |
| 1853 | if fixAllAction.Edit != nil && fixAllAction.Edit.Changes != nil { |
| 1854 | expectedURI := lsconv.FileNameToDocumentURI(f.activeFilename) |
| 1855 | for uri, edits := range *fixAllAction.Edit.Changes { |
| 1856 | if uri != expectedURI { |
| 1857 | t.Fatalf("Fix-all code action returned edits for unexpected URI %q (expected %q)", uri, expectedURI) |
| 1858 | } |
| 1859 | f.applyTextEdits(t, edits) |
| 1860 | } |
| 1861 | } |
| 1862 | |
| 1863 | actual := f.getScriptInfo(f.activeFilename).content |
| 1864 | assert.Equal(t, options.NewFileContent, actual, "File content after applying all code fixes did not match expected content.") |
| 1865 | } |
| 1866 | |
| 1867 | // VerifySourceFixAll verifies that requesting a source.fixAll code action produces the expected file content. |
| 1868 | // This tests the on-save code path where VS Code requests source.fixAll. |