QAM Hub
Home / Blog / How to Migrate Test Cases from Spreadsheets to a Test Management System

How to Migrate Test Cases from Spreadsheets to a Test Management System

By Mike Krasnovskyi, Head of Automation at QA Madness · Published 2026-08-04
Isometric illustration of a cracked spreadsheet grid on the left feeding a stream of clean structured rows into a nested test suite tree on the right, dark violet palette

To migrate test cases from a spreadsheet into a test management system, flatten the sheet into one row per test case, audit and deduplicate it before you touch the importer, map every column to a real field in the target tool, import a pilot batch of 20-30 cases first, then reconcile counts against the original file before you let anyone write to the sheet again. The import itself takes minutes. The work is in the two hours before it and the two hours after it, and that is where most migrations quietly lose data.

The takeaway in 30 seconds

We have run this migration for client teams and for our own QA department, and the pattern repeats: the tooling is not the hard part. Below is the sequence we use, the exact column layout to normalise into, the CSV mechanics that break imports, and the validation checklist that catches a bad import while it is still cheap to undo.

Side by side view of a messy test case spreadsheet and the same cases organised into suites in QAM Hub

Why spreadsheet migrations lose data

Two things are true at once. Spreadsheets are excellent at holding text, and they are unreliable as a system of record. Raymond Panko's review of the research, "What We Don't Know About Spreadsheet Errors Today" (2015), reports that across 85 intensive inspection studies auditors found errors in 94% of the spreadsheets examined, with cell error rates in field audits of 0.9-2.5% and an average of 3.9% in controlled development studies. Panko's subject was financial models, not test suites, and a wrong cell in a test case does not compound the way a wrong cell in a formula does. The relevant part is the base rate: in any human-maintained grid of a few thousand rows, some percentage of rows is wrong, and nobody knows which ones.

That matters at migration time because an import is a faithful copier. It does not evaluate whether a case is still relevant, whether two rows describe the same scenario in different words, or whether row 812 has an expected result that was true two releases ago. Import first and you have paid to move your mess into a tool where it is now harder to bulk-edit. Our longer argument about where sheets stop working is in Test Management vs Spreadsheets: When Sheets Break. This article is the mechanical half of that pair.

Step 1: Audit the sheet before you open the importer

Set a fixed cut-off. Announce that the sheet is frozen for edits on a specific date and time, and that anything added after that has to be re-entered in the new tool. Migrations that run against a moving spreadsheet produce two sources of truth and a week of arguments about which is current.

Then work through the sheet with four questions:

Two habits make the audit defensible. Work on a copy, and record what you removed with the reason in a separate tab. When someone asks in October why their case is gone, the answer should take thirty seconds to find.

Expect the sheet to shrink. In our migrations the audit consistently removes more rows than the team predicted at kick-off, and the removals are concentrated in the oldest tabs. Budget the time for it: this is the step that pays for itself, and it is the step most often skipped when someone treats the migration as an IT task with a deadline.

Step 2: Decide what you migrate and what you archive

Migrate the test cases. Archive nearly everything else. Testmo's own migration guide for teams coming from Excel and Google Sheets gives the same advice and explains why: the old tool structures runs and results differently, so reformatting history into the new schema costs real effort and produces reports nobody trusts.

A workable split:

Content in the sheetDecisionWhy
Test cases (title, preconditions, steps, expected results)MigrateThis is the asset. Everything else is metadata about it.
Suite / module / feature groupingMigrate as a hierarchy pathCheap to carry in one column, expensive to rebuild by hand afterwards.
Priority, type, tags, ownerMigrate if the values are consistentInconsistent free-text values arrive as inconsistent field values. Normalise them in the sheet first.
Requirement or ticket referencesMigrate, but import the requirements firstImporters match references against requirements that already exist and skip the rest. Load the requirements, then the cases, and the links form during the import instead of by hand afterwards.
Pass/fail columns per releaseArchiveColour-coded run columns are a report, not data. They do not map to a run model.
Defect notes written inside cellsArchive, extract anything openOpen bugs belong in the tracker. Closed ones are history.
Embedded screenshotsRebuild selectivelyThey do not survive CSV. Re-attach only to cases where the image is the expected result.
Comment threads and revision historyArchiveNothing carries them across. Keep the original file read-only if there is any audit obligation.

Keep the frozen original somewhere permanent and read-only. It costs nothing and it ends every "we lost something" conversation in the first month.

What does not survive a spreadsheet export

A CSV is plain text with delimiters. Everything a spreadsheet layers on top of text is gone the moment you export, and this surprises people who have only ever exported small files. Testiny's import documentation states plainly that attachments, images and history cannot be imported. That is not a gap in one vendor's product. It is what the format is.

Lost on exportWhat to do instead
Cell colours and conditional formattingConvert the meaning into a real column before exporting. If yellow meant "needs review", add a status column and fill it.
Merged cellsUnmerge and repeat the value down every row. Merged cells produce empty fields on the second and later rows, which is how half a suite ends up with no suite path.
Embedded images and screenshotsExport them to a folder named after the cases, then upload them to the project's image library and reference them from the text. See the section on image markers below, because this is the one attachment path a CSV can carry.
FormulasPaste as values into the export copy. A formula exports as its result at best, and as an error string at worst.
Comments and threaded repliesNothing to do. If a comment holds a real instruction, move it into the case text before you export.
Revision historyNothing to do. The new tool starts its own history from the import forward. QAM Hub keeps the last 20 versions per case with rollback, counting from version one after import.
Multiple tabsA CSV export takes one sheet. Export each tab separately, or consolidate into one sheet with a suite path column first.
Hyperlinks and rich textThe display text usually survives, the target usually does not. Paste full URLs as visible text where they matter.
Data validation and dropdown listsRecreate as custom fields in the target tool before importing, or the values arrive as free text.

Step 3: Normalise into one flat table

The importer wants a rectangle. One header row, no merged cells, no blank spacer rows, no totals row at the bottom, one sheet. Name the headers after the fields you are importing into, because most importers match a column to a field automatically when the names agree, which removes most of the manual mapping work. The layout below is built against CSV import in QAM Hub, and the same shape works for any tool that models a case as a title, a group and a block of steps.

Column headerWhat it holdsRequiredRules worth knowing
TitleOne scenario, phrased as an actionYesUp to 300 characters. Rows with an empty title are skipped and listed in the import report.
GroupFull folder hierarchy in one cellFor hierarchyUse > between levels, e.g. Web app > Checkout > Promo codes. Missing groups are created for you.
StepsAll steps for the case in one cell, numbered on separate linesIn practice yesUp to 5,000 characters. Can be switched off per project, in which case the column is ignored.
Expected ResultThe outcome that decides pass or failIn practice yesUp to 5,000 characters. Also switchable per project.
TagsTag names for filtering and groupingNoSeparate several with a semicolon. Tags that do not exist yet are created. Names up to 25 characters.
RequirementsReferences to requirements that already exist in the projectNoSemicolon separated, matched by external key such as PROJ-123 or by title. Unmatched references are skipped and reported, never created.
Automated StatusWhether the case is automatedNoNot, Yes, In Progress, Not Possible, Backlog. Anything empty or unrecognised becomes Not.
Legacy IDThe original row identifier from your sheetRecommendedNeeds a custom text field created before the import, otherwise the column is ignored.
PreconditionsState the system must be in before step 1NoA custom text-area field, up to 5,000 characters.
PriorityYour priority scaleNoA custom dropdown. Values have to match the configured options, matched case-insensitively.
TypeFunctional, regression, smoke, negativeNoCustom dropdown, same matching rule.
OwnerWho maintains the caseNoCustom text or dropdown field, depending on whether you want a fixed list.
NotesAnything with no field yetNoCustom text area. Review it after the import and empty the column.
Field reference panel in QAM Hub listing the built-in CSV import fields Title, Steps, Expected Result, Group, Automated Status, Requirements and Tags with their limits

Two details in that table cost people a re-import. Semicolons separate multiple tags and multiple requirement references, so a comma-separated tag list arrives as one long tag. And requirements are matched, never created, so import your requirements into the project first if you want the references to land as links instead of being reported as misses.

Three decisions inside that layout carry most of the risk.

One row per case, or one row per step

This is the decision that differs most between tools, and getting it wrong means re-importing. QAM Hub takes one row per test case, with all steps in a single Steps cell of up to 5,000 characters and one Expected Result for the case. Number the steps on separate lines inside the cell and keep the formatting boring.

Other tools model it differently, which matters if your sheet was itself exported from a TMS. TestRail's documentation describes both shapes: its text template uses "standard one row format", where everything for a case sits in one row, while its steps template uses a multi-row layout in which the first row carries the case fields plus step one and each following row adds another step. Testiny goes further and offers seven ways to parse steps out of a cell, including newline-separated, numbered prefixes such as "1." or "(1)", bracketed numbers and a leading asterisk. A file built for a multi-row importer will produce one case per step in a single-row importer, so check the shape before you check anything else.

The practical consequence for a spreadsheet migration: if your sheet already has one row per step, consolidate the steps into one cell per case before exporting. A short script or a concatenation in a helper column does it in minutes, and it is far cheaper than deleting several thousand one-step cases afterwards.

Hierarchy in one column

Nested groups are expressed as a path in a single cell, and the separator is a convention, not a standard. QAM Hub uses > in the Group column, as in Web app > Checkout > Promo codes, creates any missing group in the path automatically, and recognises a TestRail "Section Hierarchy" column without being told. TestRail itself uses >, Testomat's documentation shows forward slashes as in /suite name/sub-suite name, and Testiny defaults to > with the separator configurable. Never use the separator character inside your own group names, and keep the tree shallow. QAM Hub nests about six levels deep; two or three levels usually reads better in a run than six.

Custom fields have to exist first

An importer can only map a column to a field that already exists, and unmapped columns are ignored without stopping the import. That is the quiet failure mode in every tool we have tested: QAM Hub states it in its own import help, and Testiny's docs say the same. Nothing errors, the import reports success, and the column is simply not there afterwards.

So build the target project before you build the file. Create the custom fields you need, then check your sheet against what each type accepts.

Field typeAcceptsWhat happens to a bad value
TextFree text up to 300 charactersLonger content is a truncation risk, so check your longest cell first.
Text areaFree text up to 5,000 charactersSame, with far more headroom. Use this for preconditions and notes.
NumberA numeric valueText in a numeric column is the usual reason a column arrives half empty.
DropdownOne of the field's configured options, matched case-insensitivelyA value matching nothing is dropped and the field is left empty. The case still imports, and the report warns you how many rows were affected.
CheckboxYes or No, true or false, 1 or 0Anything else counts as unchecked and is reported as a warning.

The behaviour on a bad dropdown value is worth sitting with, because it is the most common way a migration looks successful and is not. "High" and "high" both match a High option, "Hi" matches nothing, and the case still imports with an empty priority. Nothing fails. You find out when someone filters by priority in September and half the suite is missing. Normalise the values in the sheet or extend the option list before you import, and read the warning counts in the report afterwards.

Screenshots: the one attachment path a CSV can carry

A CSV cannot hold an image, but it can hold a reference to one. QAM Hub writes screenshots into the Steps and Expected Result text as markers in the form [[img:ASSET-ID]], and its own CSV export uses the same notation. On import the marker is stripped out of the text and the matching asset from the project's image library is attached to the case. Up to 5 images attach per block, so a Steps field with eight markers attaches five and skips the rest.

Two constraints decide whether this helps you. Asset IDs are scoped to a project, so a marker copied into a different project resolves to nothing, and moving screenshots between projects needs the ZIP export instead. And the assets have to be in the library already, which means a first migration out of Excel still starts with exporting the images from the workbook and uploading them. Once they are in, the marker approach beats attaching images by hand to several hundred cases.

There is a setting for the messy reality of a partial migration: allowing missing image references makes the importer skip markers that match no asset instead of failing the file. Turn it on when you are importing text first and images later, which is the usual order. The duplicate assets column that our own export produces is skipped automatically, so a round-trip does not double anything.

The CSV mechanics that break imports

Most failed imports are not tool problems. They are file problems, and they repeat across every team.

SymptomCauseFix
Accented characters and Cyrillic arrive as garbageEncoding mismatch. Excel on Windows writes Windows-1252 by default, most tools read UTF-8Save as "CSV UTF-8" from Excel, or pick the matching encoding in the importer. TestRail's import wizard lets you choose Windows-1252 or UTF-8 for exactly this reason.
Columns shift halfway down the fileAn unescaped delimiter or quote inside a cellQuote every text field, escape internal quotes, and check the row where the shift begins rather than the whole file.
One case becomes several, or steps land in the wrong caseLine breaks inside cells combined with a step-parsing mode that splits on newlinesDecide whether newlines mean "new step" or "same step, new line", and make the file consistent with that setting.
Long steps arrive truncatedField limits, not file limits. Excel caps a cell at 32,767 characters per Microsoft's published limits, and the target field is usually far smaller: in QAM Hub a title holds 300 characters and Steps or Expected Result hold 5,000 eachCheck your longest cells before exporting. A case whose steps need more than 5,000 characters is two or three cases wearing one title.
Import rejected before it startsFile limits. QAM Hub accepts up to 5 MB and a maximum of 3,000 rows per file; TestRail documents a 10 MB capSplit into batches under the row cap. Batching by module is a good idea above a couple of thousand rows anyway.
All tags arrive as one long tagWrong separator inside the cell. QAM Hub splits tags and requirement references on a semicolonUse checkout;promo;regression, not commas, and keep each tag name under 25 characters.
Requirement references vanishThey are matched against requirements that already exist in the project and never created by the importImport or create the requirements first, then the test cases. Unmatched references are listed in the import report, so read it.
Version numbers become datesSpreadsheet type coercion, the classic "1.10" to 1 October problemFormat the column as text before entering values, or prefix with an apostrophe in the sheet.
Leading zeros disappear from IDsSame coercion, numeric interpretationText-format the column, or use a non-numeric prefix such as SHEET-0412.
Duplicates created on a re-runDuplicate detection is off, or keyed on a field you changed between runsKnow the detection rule. Testiny defaults to matching on folder and title, with title-only and off as alternatives. Do not rename cases between a failed import and its retry.
Curly quotes and non-breaking spaces in titlesAutocorrect in the source documentFind and replace before export. They make later search and deduplication unreliable.

One security note that has nothing to do with test management and everything to do with CSV: a cell starting with =, +, - or @ can be interpreted as a formula by whatever spreadsheet opens the file next. If your test data includes such strings, prefix them with an apostrophe in the export copy.

Step 4: Pick the method by volume

Three approaches, chosen by how many cases you are moving. The durations are our own planning figures from QA Madness migrations, not vendor numbers, and they assume the audit is done and the target project already exists.

VolumeMethodRealistic effortMain risk
Under 500 casesOne normalised CSV, single import pass, manual column mapping in the wizardHalf a day to a day of normalisation, minutes to import, 2-4 hours to validateSkipping the audit because the volume feels small
500-5,000 casesBatch by module or by template. 5-10 files, pilot batch first, then the rest in sequence3-5 working days of hands-on effort, usually spread across two calendar weeksInconsistent field values across tabs written by different people
Any volume above the file capBatching stops being optional. QAM Hub takes 3,000 rows and 5 MB per file, so a 4,000-case suite is at least two files whatever else you decideAdds an hour or two of splitting and per-batch validationLosing track of which batch covered which module
Over 5,000 casesScript it. Load the sheet into a staging table, transform there, push through the API keyed on legacy_id so reruns are idempotent2-4 weeks including reconciliation and a parallel-run periodPartial failures halfway through a batch with no way to tell what landed

Two notes on the large case. First, build the script so it can run twice without creating anything twice. Keying on legacy_id and checking for an existing record is a few extra lines and it converts a catastrophic partial failure into a re-run. Second, do the transformation in the staging table, not in the spreadsheet. Once the data is queryable you can answer "how many cases have no expected result" in one statement instead of by scrolling.

Batching by template rather than by module has one advantage worth knowing: Testmo's guide recommends splitting the export into several CSV files by template precisely because different templates need different column layouts. If half your cases are step-based and half are single-block text, that split is doing real work.

Import Test Cases dialog in QAM Hub showing the CSV upload area with a 5 MB and 3000 row limit and a delimiter selector set to auto-detect

Step 5: Run a pilot batch

Import 20-30 cases before you import 2,000. Build the pilot file with the same headers as the real one, so the automatic column matching behaves identically. Choose them deliberately: the longest case in the suite, one with special characters in the title, one with fifteen steps, one with an empty preconditions field, one from the deepest suite level, one with every custom field populated, and one from the oldest tab nobody has touched in a year. Those seven rows exercise more failure modes than a random sample of 200.

Then open them in the UI and read them as a tester would. Specifically:

If the pilot is wrong, fix the file and delete the pilot cases. Fixing 25 cases by hand is fine. Fixing 2,000 is a second migration.

Step 6: Validate after the full import

Run this list the same day the import finishes, while you still remember which batch was which.

Only after that list passes do you make the spreadsheet read-only and announce the switch. Doing it in the other order gives you a week of parallel edits in two places.

Test suite tree in QAM Hub after a spreadsheet import, showing nested suites and imported test cases with steps

Step 7: Close the spreadsheet down properly

This step gets skipped and it is the reason migrations fail six weeks after they technically succeeded. The old sheet is convenient, it is already open in someone's browser, and it has no permissions. If it stays writable, people will use it.

What works: set the file to view-only for everyone including its author, rename it with an ARCHIVED prefix and the freeze date, put a first-row note pointing at the new project, and move it out of the shared folder people browse. If your team keeps a link to it in a runbook or an onboarding doc, update those the same day. One team we worked with found six months later that new joiners were still being pointed at the archived sheet by an onboarding page nobody had edited.

Rebuilding what the CSV could not carry

After the import you have clean text in a structured tool and a list of things that did not come along. In priority order:

Requirement links. The text in requirement_ref is a reference, not a link. Converting those into real traceability is what makes coverage reporting possible, and it is worth doing while the migration still has attention on it. The method, including how to keep the matrix accurate afterwards, is in Requirements Traceability Matrix: How to Build One That Stays Accurate.

Attachments and screenshots. Upload the ones worth keeping to the project's image library, then reference them from the case text with image markers, five per block at most. Be selective: most screenshots in an old spreadsheet document a UI that has already changed, and re-attaching them buys you a suite full of misleading pictures.

Automation links. If some of these cases have automated counterparts, connect them now while the mapping is fresh in someone's head. QAM Hub links an automated test to its manual case through a TC- prefix in the test title, and one automated test can cover several manual cases.

Structure you deferred. Milestones, checklists for release readiness, and any grouping you flattened to get the import through. Building suites and cases from scratch in the tool is covered in Creating Test Suites and Test Cases.

The reverse trip: CSV as a bulk-editing tool

One thing changes after the migration that nobody mentions in migration guides. Once the cases are in a structured tool, the spreadsheet becomes useful again in a narrower role, as an editing surface rather than a system of record.

In QAM Hub, exporting a suite to CSV and re-importing it round-trips every field the importer reads, including automated status, requirements and tags. That makes the sheet the fastest way to do work the UI is slow at: retagging four hundred cases, renaming a naming convention across a module, setting automated status in bulk after an automation sprint, or fixing the priority values that arrived empty because the dropdown option did not exist yet.

Two cautions. Export, edit, re-import is a change with no undo button beyond the version history on each case, so do it on a suite rather than a whole project the first time. And since duplicate detection keys on the title, a re-import behaves differently depending on whether you changed the titles. Test that on a handful of cases in a scratch suite before you run it over four hundred, and confirm what your own project does with a title that no longer matches.

A realistic two-week plan for a mid-size suite

For roughly 1,500-3,000 cases, with one person owning it and a QA lead available for decisions:

WhenWork
Days 1-2Announce the freeze date. Copy the sheet. Inventory tabs, columns and value lists. Decide the target structure.
Days 3-5Audit: deduplicate, delete dead cases, finish or drop placeholders, normalise priority and type values, log every removal.
Day 6Create templates, custom fields and statuses in the target project. Build the flat file with the column layout above.
Day 7Pilot import of 20-30 deliberately awkward cases. Read them in the UI. Fix the file. Delete the pilot.
Days 8-9Full import in batches. Validation checklist per batch, same day.
Day 10Rebuild requirement links and re-attach the screenshots that matter. Set permissions.
Days 11-12Archive the sheet read-only. Update runbooks and onboarding docs. Walk the team through the new structure.
Days 13-14First real test run in the new tool. Fix what the run exposes, because a run always exposes something a review does not.

Under 500 cases this compresses to three or four days. Over 5,000 the audit and the reconciliation both stretch, and the scripted path adds its own development time.

Where QAM Hub fits

QAM Hub is a test management system built by QA Madness, the company that publishes this guide, so treat this section as what it is. The features relevant to a spreadsheet migration: CSV import and export for test cases, nestable suites and groups, templates and custom fields with several field types, tags, requirements and traceability, and version history that keeps the last 20 versions of a case with rollback. The importer matches a column to a field automatically when the header matches the field name, creates missing groups from the Group path, and creates tags that do not exist yet, which removes most of the manual mapping for a well-named file. The Quality Analyzer flags duplicate and vague cases, which is useful both before a migration when it runs on an early import and after one as a validation pass. Execution uses pass, fail, blocked, skip and untested statuses, with per-tester assignment and full execution history per case across runs, so the run history you build after the import stays queryable in a way a colour-coded column never was.

Three honest limits. The importer reads CSV only, so an XLSX workbook needs an export step, and it takes 5 MB and 3,000 rows per file, so large suites arrive in batches. It is a newer product with a smaller community than the incumbents, so there is less third-party material to search when you get stuck. And it is not a Jira-native app, so teams that want test cases living inside Jira issues will prefer a Jira app instead. Pricing is two straightforward per-user plans in the mid-market range. If you want the direct comparison, we keep QAM Hub vs spreadsheets and the wider category overview in What Is a Test Management System.

Coming from a tool rather than a sheet changes the calculus, because an export from a TMS carries fields a spreadsheet never had. We cover that case separately in What You Actually Lose When You Export Test Cases from TestRail.

Frequently asked questions

How do I import test cases from Excel into a test management system?

Save the sheet as CSV UTF-8 with one header row and no merged cells, make sure the columns match fields that already exist in the target tool, then use the tool's import wizard to map each column to a field. Import a pilot batch of 20-30 cases first, check them in the UI, and only then import the rest. Most tools read CSV rather than XLSX directly, so the export step is not optional.

Can I keep my test execution history when I move from spreadsheets?

Practically, no. Pass/fail columns per release are a report rather than structured run data, and there is no clean mapping from a coloured cell to a test run with an assignee, a timestamp and a result. Archive the old sheet read-only and start clean runs in the new tool. Within one or two release cycles the new history is more useful than the old one was.

What is the best CSV format for importing test cases?

UTF-8 encoded, comma delimited, every text field quoted, one header row, one sheet, no merged cells and no blank spacer rows. Name the headers after the fields in the target tool so automatic matching does the mapping. Use one column for the full group path with the separator the tool expects, keep a legacy ID column for reconciliation, and check which character separates multiple values inside a cell: QAM Hub splits tags and requirement references on a semicolon, so commas there produce one long tag. Decide up front whether a case occupies one row or one row per step, and apply that consistently.

Can I import an Excel file directly, or does it have to be CSV?

It depends on the tool, and CSV is the safer assumption. QAM Hub's importer reads CSV, so an XLSX workbook needs a save-as step first, and only the active sheet is exported each time. Testomat accepts XLSX but labels CSV and XLSX import as experimental in its own documentation. Keeping the master file as a spreadsheet and exporting a CSV per batch works well, because the spreadsheet is where you fix things between attempts.

Why does my test case import fail or create duplicates?

Failures are usually encoding mismatches, unescaped delimiters inside cells, or a file over the size or row limit. Silent partial losses are more common than outright failures: a row with an empty title is skipped and listed in the report, a requirement reference that matches nothing is skipped, a dropdown value outside the configured options does not arrive, and an unmapped column is ignored altogether. Duplicates usually mean the detection is keyed on a field that changed between attempts. QAM Hub matches on the title, Testiny on folder and title by default, so renaming cases between a failed import and its retry defeats the check either way. Fix the file, not the import settings, and delete a bad batch completely before retrying.

Should I clean up test cases before or after migrating?

Before. An importer copies faithfully, so duplicates and dead cases become real records that are then harder to bulk-edit. The exception is near-duplicate detection at scale, which is easier with a tool's analysis features than by eye, so a reasonable hybrid is a manual pass for obvious dead weight before the import and an automated duplicate pass immediately after.

How long does it take to migrate test cases from a spreadsheet?

The import runs in minutes. The project around it takes three to four days under 500 cases, roughly two calendar weeks for 1,500-3,000 cases with one person owning it, and two to four weeks above 5,000 where scripting and reconciliation dominate. The audit is the largest single block of time in every one of those, and cutting it is what produces migrations that have to be redone.

Do images and attachments transfer from Excel?

No. CSV carries text only, and embedded images are dropped at export. Export the images to a folder named after the cases, then re-attach after the import to the cases where the image genuinely is the expected result. QAM Hub allows up to 5 images per block and 10 per case, and most screenshots in an old sheet show a UI that has already changed.

Can I migrate directly from Google Sheets?

Yes, and the encoding is usually easier because Google Sheets exports UTF-8 by default, which is the source of fewer garbled-character problems than Excel's Windows-1252 default. The catch is the same: a CSV export covers one sheet at a time, so a workbook with a tab per tester or per module needs either one export per tab or a consolidation pass into a single sheet with a suite path column.

What should I do with the old spreadsheet after the migration?

Freeze it, set it view-only for everyone, rename it with an ARCHIVED prefix and the freeze date, add a first-row note pointing at the new project, and move it out of the folder people browse. Then update any runbook or onboarding page that links to it. A writable old sheet is the most common reason a technically successful migration stops being used.

References

  1. Raymond R. Panko, "What We Don't Know About Spreadsheet Errors Today: The Facts, Why We Don't Believe Them, and What We Need to Do", 2015. https://arxiv.org/pdf/1602.02601
  2. Microsoft, "Excel specifications and limits", Microsoft Support, accessed August 2026. https://support.microsoft.com/en-us/office/excel-specifications-and-limits-1672b34d-7043-467e-8e27-269d656771c3
  3. TestRail Support Center, "Import test cases from CSV or Excel", accessed August 2026. https://support.testrail.com/hc/en-us/articles/7101779988372-Import-test-cases-from-CSV-or-Excel
  4. Testiny Documentation, "Import & Export Test Cases", accessed August 2026. https://www.testiny.io/docs/test-management/test-cases/import-export/
  5. Testomat.io Docs, "Import from CSV/XLSX", accessed August 2026. https://docs.testomat.io/project/import-export/import/import-tests-from-csv-xlsx/
  6. Testmo, "How to Migrate to Testmo from Excel or Google Sheets", accessed August 2026. https://www.testmo.com/guides/how-to-migrate-to-testmo-from-excel-or-google-sheets/
  7. QAM Hub Knowledge Base, "Importing & Exporting Test Cases via CSV", August 2026. https://www.qam-hub.com/kb/import-export-csv