Repository: getmoto/moto (python)

Issue:
Cloudformation: Response to cloudformation:DescribeStacks missing `ExportName`
# Issue
When running the following code:

```python
with moto.mock_aws():
    response = boto3.client("cloudformation").describe_stacks(StackName=stack_name)
```

the items of `response["Stacks"][0]["Outputs"]` are missing the `ExportName` key, despite the export name being set when creating the CFN stack, and that value being present in real AWS responses.

## Setup
The stack in question was set up like so:
```python
with moto.mock_aws():
    with open(os.path.join(TEST_DIR, "stubs", "stack_template.json"), "r") as file:
        stack_template_str = file.read()

    boto3.client("cloudformation").create_stack(
        StackName=stack_name,
        TemplateBody=stack_template_str,
    )
```

where the `$TEST_DIR/stubs/stack_template.json` is:
```json
{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Transform": "AWS::Serverless-2016-10-31",
    "Description": "Description",
    "Resources": {
        "TestRole": {
            "Type": "AWS::IAM::Role",
            "Properties": {
                "AssumeRolePolicyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Action": "sts:AssumeRole",
                            "Principal": {
                                "Service": "lambda.amazonaws.com"
                            }
                        }
                    ]
                }
            }
        }
    },
    "Outputs": {
        "ReadTestObjectsRoleArn": {
            "Description": "ARN of the test role",
            "Value": {
                "Fn::GetAtt": [
                    "TestRole",
                    "Arn"
                ]
            },
            "Export": {
                "Name": {
                    "Fn::Sub": "${AWS::StackName}-test-role-arn"
                }
            }
        }
    }
}

```

# Workaround
My workaround for this is to patch the `moto.cloudformation.responses.DESCRIBE_STACKS_TEMPLATE` variable when running tests, changing it's `<Outputs>` section from:

```xml
<Outputs>
    {% for output in stack.stack_outputs %}
        <member>
            <OutputKey>{{ output.key }}</OutputKey>
            <OutputValue>{{ output.value }}</OutputValue>
            {% if output.description %}<Description>{{ output.description }}</Description>{% endif %}
        </member>
    {% endfor %}
</Outputs>
```

to:

```xml
<Outputs>
    {% for output in stack.stack_outputs %}
        <member>
            <OutputKey>{{ output.key }}</OutputKey>
            <OutputValue>{{ output.value }}</OutputValue>

            {% for export in stack.exports if export.value == output.value %}
                <ExportName>{{ export.name }}</ExportName>
            {% endfor %}

            {% if output.description %}<Description>{{ output.description }}</Description>{% endif %}
        </member>
    {% endfor %}
</Outputs>
```



Pull request:
CloudFormation: describe_stacks() now returns export names in the Outputs
Fixes #7870 

Patch:
diff --git a/moto/cloudformation/responses.py b/moto/cloudformation/responses.py
index c1a81441c..b17187a6e 100644
--- a/moto/cloudformation/responses.py
+++ b/moto/cloudformation/responses.py
@@ -825,6 +825,9 @@ DESCRIBE_STACKS_TEMPLATE = """<DescribeStacksResponse>
           <member>
             <OutputKey>{{ output.key }}</OutputKey>
             <OutputValue>{{ output.value }}</OutputValue>
+            {% for export in stack.exports if export.value == output.value %}
+                <ExportName>{{ export.name }}</ExportName>
+            {% endfor %}
             {% if output.description %}<Description>{{ output.description }}</Description>{% endif %}
           </member>
         {% endfor %}


Test patch:
diff --git a/tests/test_cloudformation/test_cloudformation_stack_crud_boto3.py b/tests/test_cloudformation/test_cloudformation_stack_crud_boto3.py
index 4320b1126..d34e6e4d5 100644
--- a/tests/test_cloudformation/test_cloudformation_stack_crud_boto3.py
+++ b/tests/test_cloudformation/test_cloudformation_stack_crud_boto3.py
@@ -239,16 +239,16 @@ dummy_output_template = {
     "AWSTemplateFormatVersion": "2010-09-09",
     "Description": "Stack 1",
     "Resources": {
-        "Instance": {
-            "Type": "AWS::EC2::Instance",
-            "Properties": {"ImageId": EXAMPLE_AMI_ID},
+        "mybucket": {
+            "Type": "AWS::S3::Bucket",
+            "Properties": {"Tags": [{"Key": "type", "Value": "testbucket"}]},
         }
     },
     "Outputs": {
         "StackVPC": {
             "Description": "The ID of the VPC",
             "Value": "VPCID",
-            "Export": {"Name": "My VPC ID"},
+            "Export": {"Name": "My-VPC-ID"},
         }
     },
 }
@@ -259,7 +259,7 @@ dummy_import_template = {
         "Queue": {
             "Type": "AWS::SQS::Queue",
             "Properties": {
-                "QueueName": {"Fn::ImportValue": "My VPC ID"},
+                "QueueName": {"Fn::ImportValue": "My-VPC-ID"},
                 "VisibilityTimeout": 60,
             },
         }
@@ -2325,23 +2325,33 @@ def test_stack_events():
     assert exp_metadata.get("HTTPStatusCode") == 400
 
 
-@mock_aws
+@pytest.mark.aws_verified
+@aws_verified
 def test_list_exports():
     cf_client = boto3.client("cloudformation", region_name=REGION_NAME)
     cf_resource = boto3.resource("cloudformation", region_name=REGION_NAME)
+    stack_name = f"mototest-with-exports-{str(uuid.uuid4())[0:6]}"
     stack = cf_resource.create_stack(
-        StackName=TEST_STACK_NAME, TemplateBody=dummy_output_template_json
+        StackName=stack_name, TemplateBody=dummy_output_template_json
     )
+    waiter = cf_client.get_waiter("stack_create_complete")
+    waiter.wait(StackName=stack_name)
     output_value = "VPCID"
-    exports = cf_client.list_exports()["Exports"]
-
-    assert len(stack.outputs) == 1
-    assert stack.outputs[0]["OutputValue"] == output_value
-
-    assert len(exports) == 1
-    assert exports[0]["ExportingStackId"] == stack.stack_id
-    assert exports[0]["Name"] == "My VPC ID"
-    assert exports[0]["Value"] == output_value
+    try:
+        assert len(stack.outputs) == 1
+        assert stack.outputs[0]["OutputKey"] == "StackVPC"
+        assert stack.outputs[0]["OutputValue"] == output_value
+        assert stack.outputs[0]["Description"] == "The ID of the VPC"
+        assert stack.outputs[0]["ExportName"] == "My-VPC-ID"
+
+        exports = cf_client.list_exports()["Exports"]
+
+        assert len(exports) == 1
+        assert exports[0]["ExportingStackId"] == stack.stack_id
+        assert exports[0]["Name"] == "My-VPC-ID"
+        assert exports[0]["Value"] == output_value
+    finally:
+        cf_client.delete_stack(StackName=stack_name)
 
 
 @mock_aws