Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Language Atlas (mini-courses for more languages)  Module 2 – ABAP with the open-source abaplint toolchain

ABAP without an SAP system: setup and limits

Run ABAP Unit tests on Node.js with the pinned abaplint transpiler, lay out abapGit files, and see by measurement where it differs from an SAP system.

  • Beginner
  • 15 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7, Node.js 24.21.0 and @abaplint/transpiler-cli 2.13.98
  • By MySmartCoPilot
Free lesson, Pro answers: 15 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Explain what ABAP is used for and which parts of it run outside an SAP system
  • Install Node.js 24 and the pinned abaplint packages, then run ABAP Unit tests from the command line
  • Organise ABAP source in abapGit format so linters, transpilers and SAP systems read the same files
  • Read a failing ABAP Unit run and name the test, the expected value and the actual value
  • Rewrite newer ABAP syntax as 7.02 with abaplint's downport rule and test the result

Before you start

What you’ll learn · Before you start

What you will learn

  • Explain what ABAP is used for and which parts of it run outside an SAP system
  • Install Node.js 24 and the pinned abaplint packages, then run ABAP Unit tests from the command line
  • Organise ABAP source in abapGit format so linters, transpilers and SAP systems read the same files
  • Read a failing ABAP Unit run and name the test, the expected value and the actual value
  • Rewrite newer ABAP syntax as 7.02 with abaplint's downport rule and test the result

Before you start

On this page

ABAP is the language of SAP’s application servers, and you cannot install one of those on a laptop in an afternoon. Three MIT-licensed npm packages close most of that gap: on Node.js 24, two commands turned this lesson’s class, its test class and a library of standard classes into 584 JavaScript modules and ran three ABAP Unit tests.

This lesson sets that toolchain up at pinned versions, lays the source out the way abapGit stores it, reads a passing and a failing test run, and measures where the transpiler: A compiler whose output is source code in another high-level language rather than machine code. The abaplint transpiler turns ABAP into JavaScript, which Node.js then runs. More in “How the Language Atlas works” gives another answer than an SAP system would, so that you know which results to trust before the module teaches the language itself.

ABAP runs inside SAP systems, and a large part of it runs on Node.js

SAP’s keyword documentation calls ABAP the programming interface of the Application Server ABAP, used for system programs and for application programs that are usually built on objects of the ABAP Dictionary or of CDS. The on-premise releases of SAP S/4HANA run on that server: S/4HANA 2022 uses ABAP release 7.57, the ABAP Platform 2022. If you maintain ABAP, your code lives in such a system next to SAP’s own, and every change normally starts with a logon to a development system.

The abaplint transpiler takes another route. It reads ABAP source files, checks them with abaplint’s parser and writes JavaScript that Node.js runs with the @abaplint/runtime package. The standard classes your code calls, such as cl_abap_unit_assert, the assertion class of ABAP Unit: ABAP's built-in unit test framework: local test classes declared FOR TESTING, whose test methods check results with the methods of the class cl_abap_unit_assert, such as assert_equals., come from open-abap-core, an MIT-licensed library written in ABAP that is transpiled together with your files. The transpiler’s README names abapGit, abap2UI5 and SAP’s abap-file-formats-tools as projects that run their unit tests this way on every push, and Exercism’s ABAP test runner uses it to run learners’ solutions.

Step through one run of this lesson’s first project, with the counts its session printed:

Interactive · stage by stage From three ABAP files to a test result on Node.js Step through what the two commands of a run do with the hello project, and where a failing test sends you.
From three ABAP files to a test result on Node.js, step 7 of 7. Showing abapGit files, open-abap-core added, Parsed and checked, JavaScript written, Node.js runs the tests, Exit status. In focus: fix, abapGit files.a test failedabapGit files3 files in src/open-abap-core added678 files, one commitParsed and checkedsyntax errors stop hereJavaScript written584 objects in output/Node.js runs the testsnode output/index.mjsExit status0 all passed, 1 failed

The drawing shows the whole scene; its 7 steps are listed below.

Every step as text
  1. Your files. npx abap_transpile starts with your own source: the hello class, its test class and the XML file that describes the class, three files in the src folder named in abap_transpile.json.
  2. The library. Next it reads open-abap-core from its folder, 678 files at the pinned commit. They hold the standard classes your code calls, such as cl_abap_unit_assert, written in ABAP and turned into JavaScript like your own.
  3. Parsed and checked. The transpiler parses every file with the abaplint parser and checks its syntax. A syntax error stops the run here, before any JavaScript is written.
  4. JavaScript written. It writes one JavaScript module per object, 584 of them for this project, into output, plus index.mjs, the script that runs every test class it found.
  5. The tests run. node output/index.mjs loads the runtime, then runs each test method in turn and prints a line before each one: ZCL_ATLAS_HELLO: running ltcl_greet->greets_by_name, then the other two.
  6. The exit status. When every test passes the script exits with status 0. The first failing test ends the run with status 1, which is what a build server checks.
  7. When a test fails. A failing test sends you back to the source files: fix the class or the expectation, then run both commands again. The output folder is rebuilt from the files every time.

What the transpiler cannot give you is the SAP system around the code: its screens, its database tables and their data, its users and their authorisations, its connections to other systems. The last section of this lesson runs a few of those and shows what happens. The rest of what this module teaches (data, internal tables, classes, exceptions, unit tests and SQL on a small database) runs here, and every result that would differ on an SAP system is named where it appears.

Not affiliated

Based on public information about SAP. MySmartCoPilot is not affiliated with SAP, and SAP’s real systems may differ from what this lesson describes.

Checkpoint

Check: Where ABAP runs, and what the transpiler runs

  1. Question 1 of 2 You change a class that totals invoice lines from an internal table, and the screen that shows the total to a clerk. What can you test on the transpiler?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: The class and its unit tests; the screen needs an SAP system

    The transpiler runs your logic: data, internal tables, classes, exceptions and unit tests. The parts of the SAP system around it, such as screens, real database tables, users and connections to other systems, still need an SAP system.

  2. Question 2 of 2 When the hello tests run on Node.js, where does the class cl_abap_unit_assert come from?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: From open-abap-core, a library written in ABAP and transpiled with your files

    open-abap-core is an MIT-licensed library of standard ABAP classes, such as cl_abap_unit_assert. abap_transpile.json points at its folder, and the transpiler turns it into JavaScript together with your own files.

Setup: Node.js 24, three pinned packages and one library commit

The setup takes four steps, and each one pins a version, because the transpiler changes fast: in the 30 days up to 2.13.98, the release this module’s runs were recorded with, its command-line package was published 24 times. A result recorded with one version promises nothing about the next, which is why every session of this module starts by listing its versions.

  1. Install Node.js 24. The transpiler’s README asks for Node.js 22 or newer; this module’s sessions ran on 24.21.0.
  2. Write package.json with exact versions and run npm install, which writes package-lock.json beside it. Commit both: on a build server, npm ci installs exactly what the lockfile lists.
  3. Clone open-abap-core and check out the pinned commit: git clone https://github.com/open-abap/open-abap-core.git, then git -C open-abap-core checkout dd59b82c166b09f89ce9bc668aa7a8af689075a3.
  4. Write abap_transpile.json, which tells the transpiler where your source is, where to write and where the library is.
The two configuration files of the hello project

hello/package.json

{
  "name": "atlas-hello",
  "private": true,
  "devDependencies": {
    "@abaplint/cli": "2.120.68",
    "@abaplint/runtime": "2.13.98",
    "@abaplint/transpiler-cli": "2.13.98"
  }
}

hello/abap_transpile.json

{
  "input_folder": "src",
  "output_folder": "output",
  "libs": [{ "folder": "open-abap-core" }],
  "write_unit_tests": true,
  "options": { "addCommonJS": true }
}
Setting What it does
"input_folder": "src" Where your ABAP files are
"output_folder": "output" Where the JavaScript goes; it is written again on every run
"libs": [{ "folder": "open-abap-core" }] Reads the library from the folder you cloned. With a url instead, the transpiler clones the newest commit on every run, so your results could change without any change of yours
"write_unit_tests": true Also writes output/index.mjs, the script that runs every test class
"options": { "addCommonJS": true } Writes each object as a module that imports what it uses

The first run of a project checks the versions, transpiles and runs the tests:

Versions, the transpile and the first test run Python · setup_session.py
from session import run

# The first run of a new ABAP project: Node.js and the pinned packages say their versions, the transpiler turns the
# class, its test class and the open-abap-core library into JavaScript, and Node.js runs the three ABAP Unit tests.
run("""
node --version
cd hello
npm ls
npx abap_transpile
node output/index.mjs
""")

Output

$ node --version
v24.21.0
$ cd hello
$ npm ls
atlas-hello@ .
├── @abaplint/cli@2.120.68
├── @abaplint/runtime@2.13.98
└── @abaplint/transpiler-cli@2.13.98
$ npx abap_transpile
Transpiler CLI
Using config: abap_transpile.json
3 files added from source
0 files skipped in source

Building
From folder: open-abap-core
	678 files added from lib

Output
584 objects written to disk
$ node output/index.mjs
ZCL_ATLAS_HELLO: running ltcl_greet->greets_by_name
ZCL_ATLAS_HELLO: running ltcl_greet->trims_spaces
ZCL_ATLAS_HELLO: running ltcl_greet->greets_nobody

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 setup_session.py

Read it from the top. node answered v24.21.0 and npm ls listed the three pinned packages: that is the toolchain check to repeat whenever a result surprises you. The transpiler took 3 files from src and 678 from the library, then wrote 584 objects. Each of the next three lines announces one test method before it runs. No error after them and no exit status line mean that all three passed and the run ended with status 0.

An options object without addCommonJS

When a project has an abap_transpile.json, the command uses its options as they stand, so "options": {} leaves addCommonJS off. The transpile still reports 584 objects, but the test run stops at once with ReferenceError: cl_abap_objectdescr is not defined, because the class modules no longer import the classes they build on. Keep "addCommonJS": true in every options you write.

Checkpoint

Check: A pinned setup and the first run

  1. Question 1 of 2 A colleague's abap_transpile.json names the library with "url" instead of "folder". The tests passed yesterday, and today one fails, although nobody changed a file. What is the likeliest cause?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: The transpiler cloned a newer commit of open-abap-core today

    A "url" library is cloned again on every run, so its newest commit becomes part of your build without any change of yours. A folder checked out at a pinned commit keeps the library still until you choose to move it.

  2. Question 2 of 2 The first session ends with three lines such as "ZCL_ATLAS_HELLO: running ltcl_greet->greets_by_name" and no exit status line. What does that mean?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: All three test methods ran and passed, and the run ended with status 0

    The runner prints a line before each test method. A failure would print the exception and end the run with status 1, which the session marks with [exit status 1]; here neither happened, so all three passed.

One ABAP class is three files in abapGit format

abapGit: A Git client for ABAP, written in ABAP and run inside an SAP system. It stores each ABAP object in a repository as files named after the object and its type, such as zcl_atlas_hello.clas.abap. stores every object under one naming rule: the object’s name in lower case, its type, an optional part of the object and the extension. The hello class therefore has three files:

The hello class in abapGit format

hello/src/zcl_atlas_hello.clas.abap

CLASS zcl_atlas_hello DEFINITION PUBLIC FINAL CREATE PUBLIC.
  PUBLIC SECTION.
    METHODS greet
      IMPORTING iv_name        TYPE string
      RETURNING VALUE(rv_text) TYPE string.
ENDCLASS.

CLASS zcl_atlas_hello IMPLEMENTATION.
  METHOD greet.
    DATA(lv_name) = condense( iv_name ).
    IF lv_name IS INITIAL.
      rv_text = `Hello!`.
    ELSE.
      rv_text = |Hello, { lv_name }!|.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

hello/src/zcl_atlas_hello.clas.testclasses.abap

CLASS ltcl_greet DEFINITION FINAL FOR TESTING
  DURATION SHORT RISK LEVEL HARMLESS.
  PRIVATE SECTION.
    DATA mo_hello TYPE REF TO zcl_atlas_hello.
    METHODS setup.
    METHODS greets_by_name FOR TESTING.
    METHODS trims_spaces FOR TESTING.
    METHODS greets_nobody FOR TESTING.
ENDCLASS.

CLASS ltcl_greet IMPLEMENTATION.
  METHOD setup.
    mo_hello = NEW zcl_atlas_hello( ).
  ENDMETHOD.

  METHOD greets_by_name.
    cl_abap_unit_assert=>assert_equals( act = mo_hello->greet( `Asha` )
                                        exp = `Hello, Asha!` ).
  ENDMETHOD.

  METHOD trims_spaces.
    cl_abap_unit_assert=>assert_equals( act = mo_hello->greet( `  Ravi  ` )
                                        exp = `Hello, Ravi!` ).
  ENDMETHOD.

  METHOD greets_nobody.
    cl_abap_unit_assert=>assert_equals( act = mo_hello->greet( `` )
                                        exp = `Hello!` ).
  ENDMETHOD.
ENDCLASS.

hello/src/zcl_atlas_hello.clas.xml

<?xml version="1.0" encoding="utf-8"?>
<abapGit version="v1.0.0" serializer="LCL_OBJECT_CLAS" serializer_version="v1.0.0">
 <asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
  <asx:values>
   <VSEOCLASS>
    <CLSNAME>ZCL_ATLAS_HELLO</CLSNAME>
    <LANGU>E</LANGU>
    <DESCRIPT>Atlas: a first class with unit tests</DESCRIPT>
    <STATE>1</STATE>
    <CLSCCINCL>X</CLSCCINCL>
    <FIXPT>X</FIXPT>
    <UNICODE>X</UNICODE>
    <WITH_UNIT_TESTS>X</WITH_UNIT_TESTS>
   </VSEOCLASS>
  </asx:values>
 </asx:abap>
</abapGit>

The source file holds the class definition and its implementation. The test classes file holds the local test class ltcl_greet, declared FOR TESTING, which production code cannot address and production systems do not generate, according to SAP’s documentation. The XML file holds what an SAP system keeps beside the source, such as the class name, its description and the flags FIXPT (fixed point arithmetic on) and WITH_UNIT_TESTS. A REPORT program has two files, .prog.abap and .prog.xml, and a database table has only its XML file, because it has no source code. A namespace at the start of a name becomes two # characters: abapGit’s documentation stores /FOOBAR/REPORT as #foobar#report.prog.abap.

The same three files serve three tools: abaplint checks them, the transpiler runs them, and abapGit pulls them into an SAP system as a real class. Around them, a project folder holds three kinds of content, set apart by who writes each:

The hello project folder: files you write, node_modules and open-abap-core that npm ci and git clone install, output from the transpiler.You write and commitsrc/: the class, its test classesand its XML descriptorpackage.json, package-lock.jsonand abap_transpile.jsonInstalled at pinned versionsnode_modules/: the three packagesopen-abap-core/: commit dd59b82Written by abap_transpileoutput/: 584 JavaScript modulesindex.mjs runs the testsnpm ci, git clonenpx abap_transpile

One ABAP project folder, by who writes each part

Text description of the diagram

The diagram shows the hello project folder as three boxes, from top to bottom, in the order a first run makes them.

  1. You write and commit: the src folder with the class zcl_atlas_hello.clas.abap, its test classes zcl_atlas_hello.clas.testclasses.abap and its descriptor zcl_atlas_hello.clas.xml, the configuration files package.json and abap_transpile.json, and package-lock.json, the lockfile that npm install writes beside package.json.
  2. Installed at pinned versions, by npm ci and git clone: node_modules with the three pinned packages, and open-abap-core, the library checked out at commit dd59b82.
  3. Written by npx abap_transpile: the output folder with 584 JavaScript modules and index.mjs, which runs the tests.

Commit what you write, pin what you install and never commit output: the transpiler writes it again from your files on every run.

Checkpoint

Check: ABAP objects as abapGit files

  1. Question 1 of 2 Which file holds the local test class of the class ZCL_GST_INVOICE in an abapGit repository?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: zcl_gst_invoice.clas.testclasses.abap

    abapGit names each file after its object: the name in lower case, the type, an optional part such as testclasses, and the extension. The test classes of a class are its testclasses part, in an .abap file.

  2. Question 2 of 2 Which of these belong in the Git repository of the hello project? Choose every one.

    Choose every answer that is right.

    Show the answer: Question 2 of 2

    Answer:

    • abap_transpile.json
    • The three files in src
    • package.json and package-lock.json

    Commit what you write and what pins your setup: the source, package.json with its lockfile and abap_transpile.json. Folders that are installed or generated, such as node_modules and output, are made again from those files.

A failing test names itself, both values and exit status 1

A passing run says little; a failing one says exactly where to look. This copy of the project has one wrong expectation, a full stop where the class writes an exclamation mark. The transpile log goes to a file, to keep the session short:

One wrong expectation: the test run stops with status 1 Python · failing_session.py
from session import run

# The same project with one wrong expectation in the first test. The transpile log goes to a file to keep the session
# short; the test run stops at the failing test and exits with status 1.
run("""
cd hello-wrong
npx abap_transpile > transpile.log
!node output/index.mjs
""")

Output

$ cd hello-wrong
$ npx abap_transpile > transpile.log
$ node output/index.mjs
ZCL_ATLAS_HELLO: running ltcl_greet->greets_by_name
<ref *1> kernel_cx_assert [Error]
    at cl_abap_unit_assert.assert_equals (file://output/cl_abap_unit_assert.clas.mjs:417:31)
    at async #greets_by_name (file://output/zcl_atlas_hello.clas.testclasses.mjs:35:5)
    at async run (file://output/index.mjs:36:9) {
  me: ABAPObject {
    value: [Circular *1],
    qualifiedName: undefined,
    RTTIName: undefined
  },
  INTERNAL_ID: 5,
  FRIENDS_ACCESS_INSTANCE: <ref *2> { SUPER: [Circular *2] },
  previous: ABAPObject {
    value: undefined,
    qualifiedName: 'CX_ROOT',
    RTTIName: '\\CLASS=CX_ROOT'
  },
  textid: Character {
    value: '                                ',
    constant: false,
    numeric: undefined,
    length: 32,
    extra: {}
  },
  kernel_errid: Character {
    value: '                              ',
    constant: false,
    numeric: undefined,
    length: 30,
    extra: { qualifiedName: 'CHAR30', ddicName: 'CHAR30', description: '' }
  },
  get_longtext: [AsyncFunction: if_message$get_longtext],
  get_text: [AsyncFunction: if_message$get_text],
  actual: String { value: 'Hello, Asha!', qualifiedName: 'STRING' },
  expected: String { value: 'Hello, Asha.', qualifiedName: 'STRING' },
  msg: String {
    value: "Expected 'Hello, Asha.', got 'Hello, Asha!'",
    qualifiedName: 'STRING'
  },
  EXTRA_CX: {
    INTERNAL_FILENAME: 'cl_abap_unit_assert.clas.abap',
    INTERNAL_LINE: 467
  }
}
[exit status 1]

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 failing_session.py

Three parts of that long output matter. The line before it, ZCL_ATLAS_HELLO: running ltcl_greet->greets_by_name, names the class and the test method that failed. Near the end, actual holds what the code returned, Hello, Asha!, expected holds what the test asked for, Hello, Asha., and msg puts both in one sentence. The last line, [exit status 1], is what a build server reads. Between them is the JavaScript exception that carries those values, with fields such as INTERNAL_ID that you can skip.

Look at what is missing too: trims_spaces and greets_nobody, the other two test methods, never ran. This runner stops at the first failing test, so one failure tells you nothing about the tests after it.

Counting running lines as passes

A running line is printed before a test starts, not after it passes. Two lines followed by an error mean one pass and one failure, and the tests after the failure did not run at all. Only exit status 0 means every test passed: fix the first failure, run again, and repeat until the status is 0.

Checkpoint

Check: Reading a failing ABAP Unit run

  1. Question 1 of 2 In the failing run, which value did the class itself return?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: 'Hello, Asha!', the value of actual

    In the exception of a failed assert_equals, actual holds what the code returned and expected what the test asked for, and msg puts both in one sentence: Expected 'Hello, Asha.', got 'Hello, Asha!'.

  2. Question 2 of 2 A class has five test methods. The run prints running lines for the first two, then an exception, then [exit status 1]. How many test methods passed?

    Type a number.

    A hint

    A running line is printed before a test starts, not after it passes.

    Show the answer: Question 2 of 2

    Answer: 1 tests

    The first test ran and passed, because the runner went on to the second. The second failed, and the runner stops at the first failing test, so tests three to five did not run at all.

The transpiler reads 7.02 syntax, and downport rewrites newer code

ABAP grew release by release, and code written for one system may use syntax that an older one cannot read. Walk through the releases whose syntax this module meets:

Timeline · 5 events in order The ABAP syntax this module meets, release by release Walk through the releases in order to see which syntax each one added and what the transpiler and downport do with it.
  1. 7.02

    String templates and the && operator transpiler input

    Release 7.0 with enhancement package 2 brought string templates such as |Hello, { lv_name }!|, the concatenation operator && and the decimal floating point types decfloat16 and decfloat34. The transpiler's README asks for this level of syntax as its input.

  2. 7.40 SP02

    Inline declarations, NEW and table expressions downport rewrites

    Inline declarations such as DATA(lv_name) = …, constructor operators such as NEW, VALUE and CONV, and table expressions such as lt_orders[ id = 1 ] arrived. abaplint's downport rule rewrites them as 7.02 statements, and the pinned transpiler also accepted the ones this module uses.

  3. 7.40 SP05

    @ in front of host variables

    ABAP SQL statements began to mark ABAP data objects with @, as in WHERE customer = @lv_customer. A statement that uses @ is checked in a strict mode.

  4. 7.50

    The int8 type, and Unicode only

    The 8-byte integer type int8 arrived, and from 7.50 the application server runs only as a Unicode system.

  5. 7.57

    ABAP Platform 2022

    Release 7.57 is the ABAP Platform 2022, which SAP S/4HANA 2022 on premise runs on. It is the edition of SAP's keyword documentation that this course cites.

The timeline has 5 events, from 7.02 to 7.57.

The transpiler’s README asks for 7.02 syntax and adds that many 7.50 statements and expressions are supported too; the pinned version accepted every 7.40 construct this module uses, such as NEW and inline DATA( ). When code has to run on a 7.02 system, or a tool insists on 7.02, abaplint’s downport: Rewriting ABAP written in newer syntax as equivalent older syntax, such as 7.02, so that older systems and tools accept it. abaplint's downport rule does it for you when the target version is v702. rule rewrites it. Its target is always 7.02, so the rule runs only when abaplint.json sets the syntax version v702:

abaplint finds the 7.40 syntax, rewrites it, and the tests still pass Python · downport_session.py
from session import run

# abaplint's downport rule, set to ABAP 7.02 in abaplint.json, finds the newer syntax in the hello class and rewrites
# it with --fix; the rewritten class still passes its tests.
run("""
cd downport
!npx abaplint
npx abaplint --fix
cat src/zcl_atlas_hello.clas.abap
npx abap_transpile > transpile.log
node output/index.mjs
""")

Output

$ cd downport
$ npx abaplint
abaplint 2.120.68
Using config: abaplint.json
ABAP release: v702 (SAP_BASIS 702, kernel 702, on-premise 702, cloud n/a, CE n/a)
ABAP language version: Normal

Using dependency from: ./open-abap-core/src/**/*.*

src/zcl_atlas_hello.clas.abap[10, 5]             - Outline DATA (downport) [E]
src/zcl_atlas_hello.clas.testclasses.abap[13, 5] - Use CREATE OBJECT instead of NEW (downport) [E]
abaplint: 2 issue(s) found, 3 file(s) analyzed
[exit status 1]
$ npx abaplint --fix
abaplint 2.120.68
Using config: abaplint.json
ABAP release: v702 (SAP_BASIS 702, kernel 702, on-premise 702, cloud n/a, CE n/a)
ABAP language version: Normal

Using dependency from: ./open-abap-core/src/**/*.*

	Iteration   1,   2 fixes applied, …ms, rule downport
	Parse, …ms
	Iteration   2,   0 fixes applied, …ms, rule downport
	Iteration   3,   0 fixes applied, …ms, rule downport
abaplint: 0 issue(s) found, 3 file(s) analyzed
Fixes applied
$ cat src/zcl_atlas_hello.clas.abap
CLASS zcl_atlas_hello DEFINITION PUBLIC FINAL CREATE PUBLIC.
  PUBLIC SECTION.
    METHODS greet
      IMPORTING iv_name        TYPE string
      RETURNING VALUE(rv_text) TYPE string.
ENDCLASS.

CLASS zcl_atlas_hello IMPLEMENTATION.
  METHOD greet.
    DATA lv_name TYPE string.
    lv_name = condense( iv_name ).
    IF lv_name IS INITIAL.
      rv_text = `Hello!`.
    ELSE.
      rv_text = |Hello, { lv_name }!|.
    ENDIF.
  ENDMETHOD.
ENDCLASS.
$ npx abap_transpile > transpile.log
$ node output/index.mjs
ZCL_ATLAS_HELLO: running ltcl_greet->greets_by_name
ZCL_ATLAS_HELLO: running ltcl_greet->trims_spaces
ZCL_ATLAS_HELLO: running ltcl_greet->greets_nobody

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 downport_session.py

The first run found two newer constructs and exited with status 1. npx abaplint --fix rewrote both: the class now declares lv_name with DATA and fills it in a second statement, and the test class creates its object with CREATE OBJECT instead of NEW. abaplint’s page for the rule asks you to test downported code, because a rewrite can be wrong, and the last two commands do: all three tests still pass.

Key idea

Match the syntax to the oldest system or tool that must read the code, let downport rewrite what is newer, and prove each rewrite with the tests you already have.

Checkpoint

Check: Syntax levels and downport

  1. Question 1 of 2 When does abaplint's downport rule run?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Only when abaplint.json sets the syntax version v702

    downport rewrites newer statements as 7.02 statements, and its target is always v702. abaplint.json in the downport project sets that version, which switches the rule on.

  2. Question 2 of 2 npx abaplint --fix has rewritten two statements of your class as 7.02 syntax. What do you do before you commit the change?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Run the unit tests again on the rewritten code

    A rewrite changes code, so it needs the same proof as any change. In the session, the downported class still passed its three tests.

The transpiler differs from an SAP system in ways a run can show

The transpiler runs your logic, not your SAP system, and its README lists the differences it knows: sy-sysid is always ABC, sy-mandt always 123, ABAP SQL is not aware of the client: In an SAP system, a self-contained unit of business data with a three-digit ID such as 100. A user logs on to one client, and ABAP SQL normally reads and writes only that client's rows., fixed point arithmetic is always on, strings are UCS-2 and the time zone is UTC. A program shows them as well as a test does. A REPORT writes its output with WRITE into a list the runtime keeps; this four-line wrapper loads the runtime, runs the program named on its command line and prints that list:

A report that prints where the transpiler differs, and its wrapper

limits/src/zatlas_limits.prog.abap

REPORT zatlas_limits.

DATA lv_i TYPE i.
DATA lv_d34 TYPE decfloat34.
DATA lv_text TYPE string.

WRITE / |sy-sysid: { sy-sysid }|.
WRITE / |sy-mandt: { sy-mandt }|.
WRITE / |sy-zonlo: { sy-zonlo }|.

lv_text = `😀`.
WRITE / |strlen( one emoji ): { strlen( lv_text ) }|.

lv_i = 3 * ( 1 / 3 ).
WRITE / |3 * ( 1 / 3 ) into i: { lv_i }|.

lv_d34 = 1 / 3.
WRITE / |1 / 3 into decfloat34: { lv_d34 }|.

WRITE / |7 / 2 in a template: { 7 / 2 }|.

lv_i = 2147483647.
TRY.
    lv_i = lv_i + 1.
    WRITE / |2147483647 + 1 into i: { lv_i }|.
  CATCH cx_sy_arithmetic_overflow.
    WRITE / |2147483647 + 1 into i: CX_SY_ARITHMETIC_OVERFLOW|.
ENDTRY.

AUTHORITY-CHECK OBJECT 'S_TCODE' ID 'TCD' FIELD 'SE38'.
WRITE / |AUTHORITY-CHECK S_TCODE: sy-subrc { sy-subrc }|.

limits/run-prog.mjs

import "./output/init.mjs";

await import(`./output/${process.argv[2]}.prog.mjs`);
console.log(abap.console.get());
The report run on the transpiler Python · limits_session.py
from session import run

# A REPORT program that prints where the transpiler's results differ from an SAP system's, run through the wrapper
# run-prog.mjs, which loads the runtime, runs the program it is given and prints its WRITE output; then two programs
# that need an SAP system, a screen and a remote function call, which stop with an error.
run("""
cd limits
npx abap_transpile > transpile.log
node run-prog.mjs zatlas_limits
!node run-prog.mjs zatlas_screen
!node run-prog.mjs zatlas_rfc
""")

Output

$ cd limits
$ npx abap_transpile > transpile.log
$ node run-prog.mjs zatlas_limits
sy-sysid: ABC
sy-mandt: 123
sy-zonlo: UTC
strlen( one emoji ): 2
3 * ( 1 / 3 ) into i: 1
1 / 3 into decfloat34: 0.3333333333333333
7 / 2 in a template: 3.5000000000000000
2147483647 + 1 into i: 2147483648
AUTHORITY-CHECK S_TCODE: sy-subrc 0
$ node run-prog.mjs zatlas_screen
file://output/zatlas_screen.prog.mjs:4
throw new Error("CallScreen, not supported, transpiler");
      ^

Error: CallScreen, not supported, transpiler
    at file://output/zatlas_screen.prog.mjs:4:7

Node.js v24.21.0
[exit status 1]
$ node run-prog.mjs zatlas_rfc
…/abaplint-2.13.98/node_modules/@abaplint/runtime/build/src/statements/call_function.js:58
                throw new Error(`RFC destination ${options.destination} does not exist`);
                      ^

Error: RFC destination PRD does not exist
    at CallFunction.callFunction (…/abaplint-2.13.98/node_modules/@abaplint/runtime/build/src/statements/call_function.js:58:23)
    at Statements.callFunction (…/abaplint-2.13.98/node_modules/@abaplint/runtime/build/src/statements/index.js:143:63)
    at file://output/zatlas_rfc.prog.mjs:4:23

Node.js v24.21.0
[exit status 1]

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 limits_session.py

Beside each printed line, here is what an SAP system does, from SAP’s own documentation:

Line of the report The transpiler printed An SAP system
sy-sysid, sy-mandt ABC and 123 The system’s own ID and the client you logged on to
sy-zonlo UTC The time zone of your user
strlen( one emoji ) 2 2 as well: strlen counts a surrogate pair as two UCS-2 characters
3 * ( 1 / 3 ) into i 1 0: in calculation type i, every interim result is rounded, and 1 / 3 rounds to 0
1 / 3 into decfloat34 16 threes 34 threes: decfloat34 keeps 34 places
{ 7 / 2 } in a template 3.5000000000000000 A calculation of type i, because only the operands count, which rounds 3.5 to 4
2147483647 + 1 into i 2147483648 The exception CX_SY_ARITHMETIC_OVERFLOW, because the result is outside i
AUTHORITY-CHECK sy-subrc 0 0 if your user has the authorisation, otherwise 4 or more

Some SAP features do not run at all, as the last two commands of the session show: CALL SCREEN 100 stopped with “CallScreen, not supported, transpiler”, and a remote function call to a destination named PRD stopped with “RFC destination PRD does not exist”. The later lessons of the module name four more differences where they matter: a formatting option of string templates, binary searches that miss, CLEANUP blocks and host variables in SQL.

Key idea

Trust the transpiler for the logic of your classes, tables and tests, and check on an SAP system anything this table names before you rely on it.

Checkpoint

Check: Where the transpiler differs from an SAP system

  1. Question 1 of 2 On an SAP system, lv_i is of type i. What does lv_i hold after lv_i = 3 * ( 1 / 3 ).?

    Type a number.

    A hint

    In calculation type i, every interim result that is not a whole number is rounded at once.

    Show the answer: Question 1 of 2

    Answer: 0

    With only integer operands and an integer target, the calculation type is i. 1 / 3 is rounded commercially to 0 before the multiplication, so the result is 3 * 0 = 0; SAP's numeric cheat sheet asserts exactly this. The transpiler printed 1, because it does not round the interim result.

  2. Question 2 of 2 Your class calls AUTHORITY-CHECK and refuses to post an invoice when sy-subrc is not 0. A unit test on the transpiler checks that a user without the authorisation is refused. What happens, and what do you do?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: The test fails, because AUTHORITY-CHECK returns 0 on the transpiler; test the refusal on an SAP system or put the check behind an interface the test can replace

    On an SAP system, AUTHORITY-CHECK returns 0 when your user has the authorisation, and 4 or more when it has not. On the transpiler it returned 0, so a test of the refusal needs an SAP system, or an interface around the check that a test can replace with a stand-in that refuses.

Practise: name the abapGit files of an object

A script that checks a repository, or copies objects from one repository to another, has to know which files belong to which object. The exercise writes that rule as two Python functions, from abapGit’s naming convention, and its sample tests use the files of this lesson’s projects.

Exercise · Easy · Python

Name the abapGit files of an ABAP object

A script that checks an ABAP repository, or one that copies objects between repositories, needs to know which files belong to which object. Write two functions in abapgit_files.py, following abapGit's naming rule: the object's name in lower case, a dot, the object type in lower case, an optional object part, then the extension. A namespace /NAME/ at the start of an object name becomes #name# in the file name.

files_of(object_type, name, test_classes=False) returns the sorted list of file names of one object:

  • "CLAS": <name>.clas.abap and <name>.clas.xml, plus <name>.clas.testclasses.abap when test_classes is true.
  • "PROG": <name>.prog.abap and <name>.prog.xml.
  • "INTF": <name>.intf.abap and <name>.intf.xml.
  • "TABL": only <name>.tabl.xml, because a database table has no source code.
  • Any other type raises ValueError.

object_of(file_name) goes the other way and returns a tuple (object_type, object_name) in upper case, with #name# turned back into /NAME/. It returns None for a file that belongs to no object of those four types, such as package.json, abap_transpile.json or package.devc.xml, whose name is a fixed word rather than an object name, and for a name without all three pieces, such as zcl_atlas_hello.clas or .abapgit.xml.

  • files_of("CLAS", "ZCL_ATLAS_HELLO", True) is ["zcl_atlas_hello.clas.abap", "zcl_atlas_hello.clas.testclasses.abap", "zcl_atlas_hello.clas.xml"].
  • files_of("PROG", "/FOOBAR/REPORT") is ["#foobar#report.prog.abap", "#foobar#report.prog.xml"].
  • object_of("zcl_atlas_hello.clas.testclasses.abap") is ("CLAS", "ZCL_ATLAS_HELLO").

The sample tests use the files of this lesson's projects.

Starter code · abapgit_files.py

def files_of(object_type, name, test_classes=False):
    """Return the sorted file names abapGit uses for one ABAP object, as the prompt describes."""
    # Replace this line with your code.
    return []


def object_of(file_name):
    """Return (object_type, object_name) in upper case for an object's file, or None for any other file."""
    # Replace this line with your code.
    return None
The sample tests · test_abapgit_files.py
from abapgit_files import files_of, object_of


def test_class_with_its_test_classes():
    """names the three files of the hello class"""
    assert files_of("CLAS", "ZCL_ATLAS_HELLO", True) == [
        "zcl_atlas_hello.clas.abap",
        "zcl_atlas_hello.clas.testclasses.abap",
        "zcl_atlas_hello.clas.xml",
    ]


def test_class_without_test_classes():
    """leaves out the test include when the class has no tests"""
    assert files_of("CLAS", "ZCX_INSUFFICIENT_FUNDS") == ["zcx_insufficient_funds.clas.abap", "zcx_insufficient_funds.clas.xml"]


def test_program_and_table():
    """names the two files of a program and the one file of a table"""
    assert files_of("PROG", "ZATLAS_LIMITS") == ["zatlas_limits.prog.abap", "zatlas_limits.prog.xml"]
    assert files_of("TABL", "ZATLAS_ORDER") == ["zatlas_order.tabl.xml"]


def test_namespace():
    """turns /FOOBAR/ into #foobar#"""
    assert files_of("PROG", "/FOOBAR/REPORT") == ["#foobar#report.prog.abap", "#foobar#report.prog.xml"]


def test_object_of_a_test_include():
    """finds the class a test include belongs to"""
    assert object_of("zcl_atlas_hello.clas.testclasses.abap") == ("CLAS", "ZCL_ATLAS_HELLO")
    assert object_of("zatlas_limits.prog.xml") == ("PROG", "ZATLAS_LIMITS")


def test_object_of_a_namespace():
    """turns #foobar# back into /FOOBAR/"""
    assert object_of("#foobar#report.prog.abap") == ("PROG", "/FOOBAR/REPORT")


def test_files_of_no_object():
    """returns None for the project's other files"""
    assert object_of("package.json") is None
    assert object_of("abap_transpile.json") is None
    assert object_of("package.devc.xml") is None


def test_names_that_are_not_object_files():
    """returns None for a name without an extension and for the repository's settings file"""
    assert object_of("zcl_atlas_hello.clas") is None
    assert object_of(".abapgit.xml") is None


def test_unknown_type():
    """refuses a type it does not know"""
    try:
        files_of("FUGR", "ZATLAS_GROUP")
    except ValueError:
        return
    assert False, "files_of should raise ValueError for an unknown type such as FUGR"
A hint

For object_of, split the file name at its dots: the first piece is the object's name and the second its type, and anything after them is the object part and the extension. name.upper() and str.replace do the case and the # characters; check the type against the four you know before you build the tuple.

The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Then check yourself on the six ideas, from where ABAP runs to what the transpiler cannot show you; your own answers decide the order, shakiest idea first:

Practice that adapts to you

Practise this lesson

18 questions about 6 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 18 Where does ABAP code normally run?

    Choose one answer.

    Show the answer: Question 1 of 18

    Answer: On SAP's Application Server ABAP, for example in an SAP S/4HANA system

    ABAP is the language of SAP's Application Server ABAP. SAP S/4HANA on premise runs on that server; release 7.57, the ABAP Platform 2022, is the one S/4HANA 2022 uses.

  2. Question 2 of 18 What does the abaplint transpiler write?

    Choose one answer.

    Show the answer: Question 2 of 18

    Answer: JavaScript modules that Node.js runs with the @abaplint/runtime package

    The transpiler reads ABAP source, checks it with abaplint's parser and writes one JavaScript module per object. Node.js runs them with the runtime package, and index.mjs runs the tests.

  3. Question 3 of 18 A colleague says ABAP unit tests can only run after a logon to the development system. Which fact from this lesson answers that best?

    Choose one answer.

    Show the answer: Question 3 of 18

    Answer: The transpiler's README names abapGit, abap2UI5 and abap-file-formats-tools as projects that run their unit tests on it on every push

    Projects such as abapGit and abap2UI5 run their ABAP Unit tests on the transpiler on every push. Tests that need the SAP system itself, such as authorisations or real database tables, still run there.

  4. Question 4 of 18 Which Node.js does the transpiler's README ask for, and which did this module's sessions run on?

    Choose one answer.

    Show the answer: Question 4 of 18

    Answer: Node.js 22 or newer; the sessions ran on 24.21.0

    The README asks for Node.js 22 or newer. This module pins 24.21.0, the version every session reports first, so a run you repeat can start from the same Node.js.

  5. Question 5 of 18 A build server must install exactly the npm package versions your tests passed with. What do you give it?

    Choose one answer.

    Show the answer: Question 5 of 18

    Answer: The committed package-lock.json, installed with npm ci

    npm install writes package-lock.json with the exact versions it resolved. Commit it with package.json, and npm ci on a build server installs exactly those versions.

  6. Question 6 of 18 Your abap_transpile.json has "options": {}. The transpile reports 584 objects, but node output/index.mjs stops with ReferenceError: cl_abap_objectdescr is not defined. What do you change?

    Choose one answer.

    Show the answer: Question 6 of 18

    Answer: Set "options": { "addCommonJS": true }

    With a config file, the command uses its options as they stand. "options": {} leaves addCommonJS off, so each class module refers to its superclass without importing it, and the first such class stops the run.

  7. Question 7 of 18 What does the file zcl_atlas_hello.clas.xml hold?

    Choose one answer.

    Show the answer: Question 7 of 18

    Answer: What an SAP system keeps beside the source, such as the class name, its description and flags like FIXPT and WITH_UNIT_TESTS

    abapGit keeps the code of a class in .abap files and its settings in an XML descriptor: its name, its description, and flags such as FIXPT (fixed point arithmetic) and WITH_UNIT_TESTS.

  8. Question 8 of 18 What file name does abapGit give the source of the program /ACME/PAYROLL?

    Choose one answer.

    Show the answer: Question 8 of 18

    Answer: #acme#payroll.prog.abap

    abapGit's documentation stores /FOOBAR/REPORT as #foobar#report.prog.abap: the namespace's slashes become #, and the whole name is written in lower case, followed by the type and the extension.

  9. Question 9 of 18 How many files does a database table have in abapGit format?

    Type a number.

    Show the answer: Question 9 of 18

    Answer: 1 files

    A database table has no source code, so abapGit stores it as one XML file, such as zatlas_order.tabl.xml. A program has two files and a class with tests three.

  10. Question 10 of 18 In the output of a failed assert_equals, which field puts the expected and the actual value in one sentence?

    Choose one answer.

    Show the answer: Question 10 of 18

    Answer: msg

    actual and expected hold the two values, and msg says them in one sentence. The rest of the object dump is the JavaScript exception that carries them.

  11. Question 11 of 18 A build server must stop when any ABAP Unit test fails. What does it check after node output/index.mjs?

    Choose one answer.

    Show the answer: Question 11 of 18

    Answer: The exit status, which is 1 after a failing test and 0 when every test passed

    The exit status is the contract between the test run and the build: 0 when every test passed, 1 when one failed, as the failing session shows with [exit status 1].

  12. Question 12 of 18 You fix a failing test 1 and run again. Now the run prints running lines for tests 1 to 4 and fails in test 4. What do you know about tests 2 and 3?

    Choose one answer.

    Show the answer: Question 12 of 18

    Answer: They ran and passed, because the runner only moved on after each of them finished without an error

    The runner stops at the first failing test. Reaching test 4 means tests 1 to 3 finished without an error, so they passed; the tests after 4 have not run yet.

  13. Question 13 of 18 In which release did string templates such as |Hello, { lv_name }!| arrive?

    Choose one answer.

    Show the answer: Question 13 of 18

    Answer: Release 7.0, enhancement package 2 (7.02)

    String templates, the concatenation operator && and the decfloat types came with 7.02, the syntax level the transpiler's README asks for. That is why templates need no downport.

  14. Question 14 of 18 What did downport make of DATA(lv_name) = condense( iv_name ). in the hello class?

    Choose one answer.

    Show the answer: Question 14 of 18

    Answer: DATA lv_name TYPE string. followed by lv_name = condense( iv_name ).

    Inline declarations arrived with 7.40 SP02. downport outlines the declaration: a DATA statement with the type, then an ordinary assignment, which 7.02 can read.

  15. Question 15 of 18 A class must be pulled into a system on release 7.02 and uses VALUE #( ... ) and lt_orders[ id = 1 ]. What do you do?

    Choose one answer.

    Show the answer: Question 15 of 18

    Answer: Run abaplint with the syntax version v702, apply downport's fixes and rerun the tests

    VALUE and table expressions arrived with 7.40 SP02, so a 7.02 system cannot read them. abaplint's downport rule, switched on by the syntax version v702, rewrites newer statements one step at a time, and the tests check the result.

  16. Question 16 of 18 What did sy-sysid hold in the limits report on the transpiler?

    Choose one answer.

    Show the answer: Question 16 of 18

    Answer: ABC

    On the transpiler, sy-sysid is always ABC and sy-mandt always 123. Code that branches on the system or the client therefore behaves the same everywhere there, and differently on a real system.

  17. Question 17 of 18 By SAP's rules for an embedded expression, what does the template |{ 7 / 2 }| calculate on an SAP system?

    Type a number.

    A hint

    Only the operands decide the calculation type of an embedded expression, and both are integers.

    Show the answer: Question 17 of 18

    Answer: 4

    SAP's documentation says that only the operands of an embedded expression count for its calculation type. 7 and 2 are integers, so the calculation type is i, and 3.5 is rounded commercially to 4. The transpiler printed 3.5000000000000000, which is why this module assigns arithmetic to a typed variable before embedding it.

  18. Question 18 of 18 Which results of a transpiler run would you check on an SAP system before relying on them? Choose every one.

    Choose every answer that is right.

    Show the answer: Question 18 of 18

    Answer:

    • A total computed as lv_total = lv_price * ( lv_rate / 100 ) in type i
    • A test that an AUTHORITY-CHECK refuses a user

    Check on an SAP system whatever the table of differences names: interim rounding, decfloat34 precision, embedded arithmetic, overflow, client handling and authorisations. Plain logic over strings, integers and internal tables runs the same.

Interview questions

Warm-up (fresher to mid-level): What does the abaplint transpiler do, and what can it not do for an ABAP team?

It turns ABAP source files into JavaScript that Node.js runs, together with open-abap-core, an MIT-licensed library of standard classes such as cl_abap_unit_assert. A team can therefore run its ABAP Unit tests on any computer or build server, on every push, without logging on to an SAP system, as abapGit and abap2UI5 do. It runs the logic of classes, internal tables, exceptions and tests. It does not give you the SAP system: screens and SAP GUI, remote function calls, real database tables with their data, users and authorisations. Some results also differ, because the transpiler is a different runtime: sy-sysid is always ABC, SQL ignores clients, interim results of integer arithmetic are not rounded, and an AUTHORITY-CHECK always passes. So the transpiler is a fast first check, and anything that touches those parts is tested again on an SAP system.

Two harder questions follow, about running ABAP tests away from the SAP system and about results that disagree:

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Mid to senior

    Your team wants its ABAP Unit tests to run on every pull request, without anyone logging on to an SAP system. How would you set that up, and what would you still test on the SAP system?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Mid to staff

    A unit test passes on the transpiler and fails on your SAP development system with the same code. How do you find out which result is right, and what do you change?

    Model answer, Pro. First step and follow-ups

Flashcards · 8 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. How does ABAP code run on a laptop without an SAP system?

    The abaplint transpiler writes JavaScript from the ABAP files, Node.js runs it with @abaplint/runtime, and open-abap-core, an ABAP library of standard classes such as cl_abap_unit_assert, is transpiled with your code.

  2. Why does the ABAP setup read open-abap-core from a local clone at one commit, not from a url?

    Given a url, the transpiler clones the newest commit on every run, so a result could change with no change of yours. A pinned local folder keeps every run repeatable.

  3. Which files does abapGit keep for the class ZCL_ATLAS_HELLO?

    zcl_atlas_hello.clas.abap for the source, zcl_atlas_hello.clas.testclasses.abap for its local test classes, and zcl_atlas_hello.clas.xml for what the system keeps beside the code, such as the description.

  4. The ABAP Unit run printed a running line for a test. Did that test pass?

    Not necessarily: the line is printed before the test starts. The runner stops at the first failure, so later tests never run, and only exit status 0 says that all of them passed.

  5. What does abaplint's downport rule do, and when is it active?

    It rewrites newer syntax, such as NEW and inline DATA( ), as ABAP 7.02 statements. It works only when abaplint.json sets the syntax version v702, and the existing tests then prove the rewrite.

  6. What do sy-sysid, sy-mandt and an AUTHORITY-CHECK give on the transpiler?

    Always ABC and 123, and a check that passes with sy-subrc 0. An SAP system gives its own ID, the client you logged on to, and 4 or more when your user lacks the authorisation.

  7. 3 * ( 1 / 3 ) is assigned to a variable of type i. What do the transpiler and an SAP system store?

    1 on the transpiler, 0 on an SAP system: in calculation type i, SAP rounds every interim result, so 1 / 3 is already 0.

  8. What breaks when an abap_transpile.json has "options": {} instead of keeping addCommonJS?

    Transpiling looks fine, but running the tests fails at once with ReferenceError: cl_abap_objectdescr is not defined: without addCommonJS the class modules do not import the classes they depend on.

Key takeaways

  • ABAP runs inside SAP’s application servers, and the abaplint transpiler runs a large part of it on Node.js, with open-abap-core supplying the standard classes.
  • A reproducible setup pins Node.js 24, three exact npm versions with a lockfile and one commit of open-abap-core, and every run starts by listing those versions.
  • abapGit stores an object as files named after the object and its type, so a class is its source, its test classes and an XML descriptor that abaplint, the transpiler and an SAP system all read.
  • A failing ABAP Unit run names the test, prints the actual and expected values and exits with status 1, and the tests after the first failure do not run.
  • abaplint’s downport rule rewrites 7.40 syntax as 7.02, and the tests prove the rewrite.
  • The transpiler’s results differ from an SAP system’s in measurable ways, such as unrounded interim results, a 16-digit decfloat34 and authorisation checks that always pass, so those cases are checked on an SAP system.

Terms in this lesson

ABAP Unit
ABAP's built-in unit test framework: local test classes declared FOR TESTING, whose test methods check results with the methods of the class cl_abap_unit_assert, such as assert_equals.
abapGit
A Git client for ABAP, written in ABAP and run inside an SAP system. It stores each ABAP object in a repository as files named after the object and its type, such as zcl_atlas_hello.clas.abap.
client
In an SAP system, a self-contained unit of business data with a three-digit ID such as 100. A user logs on to one client, and ABAP SQL normally reads and writes only that client's rows.
downport
Rewriting ABAP written in newer syntax as equivalent older syntax, such as 7.02, so that older systems and tools accept it. abaplint's downport rule does it for you when the target version is v702.

References

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.